/*
  Copyright (c) 1988 Commodore-Amiga, Inc.
 
  Executables based on this information may be used in software
  for Commodore Amiga computers.  All other rights reserved.
 
  This information is provided "as is"; no warranties are made.
  All use is at your own risk, and no liability or responsibility is assumed.
*/

#include "exec/types.h"
#include "exec/libraries.h"
#include "exec/memory.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"

#define QTOUPPER(c)      ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c))
#define MAXCHARS	4096

#undef  BADDR
#define BADDR(x)        ((APTR)((LONG)x << 2))

struct DosList {
    BPTR                dol_Next;        /* bptr to next device list */
    LONG                dol_Type;        /* see DLT below */
    struct MsgPort     *dol_Task;        /* ptr to handler task */
    BPTR            	dol_Lock;
    union {
	struct {
    	BSTR			*dol_Handler;
    	LONG			dol_StackSize;
    	LONG			dol_Priority;
    	ULONG			dol_Startup;
    	BPTR            	dol_SegList;
    	BPTR            	dol_GlobVec;
	} dol_handler;

       struct {
        struct DateStamp    	dol_VolumeDate;  /* creation date */
        BPTR                	dol_LockList;    /* outstanding locks */
        LONG                	dol_DiskType;    /* 'DOS', etc */
	} dol_volume;

    } dol_misc;

    BSTR                *dol_Name;        /* bptr to bcpl name */
};

struct DosEnvec {
    ULONG de_TableSize;      /* Size of Environment vector */
    ULONG de_SizeBlock;      /* in longwords: standard value is 128 */
    ULONG de_SecOrg;         /* not used; must be 0 */
    ULONG de_Surfaces;       /* # of heads (surfaces). drive specific */
    ULONG de_SectorPerBlock; /* not used; must be 1 */
    ULONG de_BlocksPerTrack; /* blocks per track. drive specific */
    ULONG de_Reserved;       /* DOS reserved blocks at start of partition. */
    ULONG de_PreAlloc;       /* DOS reserved blocks at end of partition */
    ULONG de_Interleave;     /* usually 0 */
    ULONG de_LowCyl;         /* starting cylinder. typically 0 */
    ULONG de_HighCyl;        /* max cylinder.  drive specific */
    ULONG de_NumBuffers;     /* Initial # DOS of buffers.  */
    ULONG de_BufMemType;     /* type of mem to allocate for buffers */
    ULONG de_MaxTransfer;    /* Maximum number of blocks to transfer at a time */
    ULONG de_Mask;           /* Address Mask to block out certain memory */
    LONG  de_BootPri;        /* Boot priority for autoboot */
    ULONG de_DosType;        /* ASCII (HEX) string showing filesystem type;
			     * 0X444F5300 is old filesystem,
			     * 0X444F5301 is fast file system */
};

struct FileSysStartupMsg {
ULONG       fssm_Unit;      /* exec unit number for this device */
BSTR        fssm_Device;    /* null terminated bstring to the device name */
BPTR        fssm_Environ;   /* ptr to environment table (see above) */
ULONG       fssm_Flags;     /* flags for OpenDevice() */
};

UBYTE *buffer,*point, *base;	/* for the output buffer */
int len;

extern struct Library *DOSBase;

main(argc,argv)
int argc;
UBYTE *argv[];
{
ULONG type;
BPTR seglist;
struct MsgPort *task;
UBYTE *name, *handler, *devicename,*p;
ULONG  deviceunit,deviceflags;
ULONG file;
int i;
BOOL flags[3];		/* used for argument parsing */

struct  DosLibrary   *dosLibrary;
struct  RootNode     *RootNode;
struct  DosInfo      *dosInfo;
struct  DosList      *DevInfo;
struct  FileSysStartupMsg *startup;
struct  DosEnvec *env;
UBYTE b[255];

    if(*argv[argc-1]=='?') {
	printf("Usage: %ls DEVS|VOLS|DIRS\n",argv[0]);
	exit(0);
    }

    if(argc == 1) {
	flags[0]=TRUE;
	flags[1]=TRUE;
	flags[2]=TRUE;
    }
    else {
	flags[0]=0;
	flags[1]=0;
	flags[2]=0;

        for(i=1; i<argc; i++) {
	    if (!(strcmpi("devs",argv[i])))flags[0]=TRUE;
	    if (!(strcmpi("vols",argv[i])))flags[1]=TRUE;
	    if (!(strcmpi("dirs",argv[i])))flags[2]=TRUE;
	}
    }
dosLibrary = (struct DosLibrary *)DOSBase;
RootNode = (struct RootNode *)dosLibrary->dl_Root;
dosInfo = (struct DosInfo *)BADDR(RootNode->rn_Info);
DevInfo = (struct DosList *)BADDR(dosInfo->di_DevInfo);

if(!(buffer=(UBYTE *)AllocMem(MAXCHARS,MEMF_PUBLIC|MEMF_CLEAR)))exit(20);
point = buffer;

Forbid();
/* walk the device list */
while ((DevInfo != NULL) && (!(SetSignal(0,0) & SIGBREAKF_CTRL_C))) { 

    type = DevInfo->dol_Type;
    task = DevInfo->dol_Task;
    name = (char *)BADDR(DevInfo->dol_Name)+1;

    if((type == DLT_DEVICE) && (flags[0])) {
        sprintf(b,"Device: %ls at %lx, task is %lx ",name,DevInfo,task);
	bp(b);
	if(task)bp("(resident)\n");
	else {
	    bp(" (not resident)\n");

	    seglist = DevInfo->dol_misc.dol_handler.dol_SegList;
	    if(seglist==0) {
		sprintf(b,"   code not in memory\n");
		bp(b);
	    }
	    else {
		sprintf(b,"  code is at %lx\n",BADDR(seglist));
		bp(b);
	    }
	    handler=(char *)BADDR(DevInfo->dol_misc.dol_handler.dol_Handler)+1;
	    if(handler) {
		sprintf(b,"  handler is  %ls\n\017",handler);
		bp(b);
	    }
	    sprintf(b,"  stacksize is %ld\n",
		DevInfo->dol_misc.dol_handler.dol_StackSize);
	    bp(b);
	    sprintf(b,"  priority is %ld\n",
		DevInfo->dol_misc.dol_handler.dol_Priority);
	    bp(b);
	    sprintf(b,"  globvec is  %lx\n",
		BADDR(DevInfo->dol_misc.dol_handler.dol_GlobVec));
	    bp(b);
	}
	if(DevInfo->dol_misc.dol_handler.dol_Startup > 2) {
	    startup=(struct FileSysStartupMsg *)
		BADDR(DevInfo->dol_misc.dol_handler.dol_Startup);
	    devicename  = (char *)BADDR(startup->fssm_Device)+1;
	    env  = (struct DosEnvec *)(BADDR(startup->fssm_Environ));
	    deviceunit  = startup->fssm_Unit;
	    deviceflags = startup->fssm_Flags;
	    sprintf(b,"  Environment vector size %ld\n",(ULONG)env->de_TableSize);
	    bp(b);
	    sprintf(b,"|     Device name is %s, unit is %ld\n",
		devicename,deviceunit);
	    bp(b);
	    sprintf(b,"|     Surfaces = %ld, BlocksPerTrack = %ld\n",
		env->de_Surfaces,env->de_BlocksPerTrack);
	    bp(b);
	    sprintf(b,"|     Reserved = %ld, LowCyl=%ld, HighCyl=%ld\n",
		env->de_Reserved,env->de_LowCyl,env->de_HighCyl);
	    bp(b);
	    sprintf(b,"|     NumNuffers = %ld, BufMemType = %ld\n",
		env->de_NumBuffers,env->de_BufMemType);
	    bp(b);
	    if(env->de_TableSize > 12) {
	        sprintf(b,"|     MaxTransfer = %ld, Mask = %lx, BootPri = %ld\n",
			env->de_MaxTransfer,env->de_Mask, env->de_BootPri);
		bp(b);
	        sprintf(b,"|     DosType is %lx\n",env->de_DosType);
		bp(b);
	    }
	}
	else bp("  No environment vector\n");
    }
    else if ((type == DLT_VOLUME) & (flags[1])) {
        sprintf(b,"Volume: %ls at %lx, File task is %lx ",name,DevInfo,task);
	bp(b);
	if (task)bp("[Mounted]\n");
	else bp("[Not Mounted]\n");
	sprintf(b,"  LockList is %lx\n",
		BADDR(DevInfo->dol_misc.dol_volume.dol_LockList));
	bp(b);
        sprintf(b,"  DiskType is %lx\n",
		DevInfo->dol_misc.dol_volume.dol_DiskType);
	bp(b);
    }
    else if ((type == DLT_DIRECTORY) && (flags[2])) {
        sprintf(b,"Directory: %ls at %lx, FileSystem task is %lx, lock is %lx\n",name,DevInfo,task,DevInfo->dol_Lock);
	bp(b);
    }
    DevInfo = (struct DosList *)BADDR(DevInfo->dol_Next);
}

Permit();
    len = point-buffer;
    point = buffer;
    base = buffer;
    for(i=0; i<len; i++) {
	if((UBYTE)*point++ == 0) {
	    printf("%s",base);
	    base = point;
	}
    }

FreeMem(buffer,MAXCHARS);
exit(0);
}

strcmpi(str1, str2)
char *str1,*str2;
{
        UBYTE *astr =str1;
	UBYTE *bstr =str2;
	UBYTE c;

    while ( (c = QTOUPPER(*astr)) && (c == QTOUPPER(*bstr)))
    astr++, bstr++;
    if( ! c ) return ( 0 );
    if( c < *bstr ) return( -1 );
    return( 1 );
}


strlen( str )
UBYTE *str;
{
    UBYTE *pt ;

    for ( pt=str ; *pt != '\0' ; pt++ );
    return( pt-str );
}


bp(s)
UBYTE *s;
{
int i;

i=strlen(s);
if((point+i) < (buffer+MAXCHARS))sprintf(point,s);
point += (i+1);
}

