/****************************************************************************
                               Proc-Handler
                            (c) 1994 Jan Kautz


You may use this Source-Code for anything you want, if you don't remove the
copyright and if you mention my name.

****************************************************************************/

#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>
#include <libraries/multiuser.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <exec/memory.h>
#include <proto/multiuser.h>
#include <proto/exec.h>
#include <proto/dos.h>


/*
so?: static and global Vars, ok ?
*/

/*************************** Debugging ****************************/

/*
#define TEST_HANDLER
*/


#ifdef TEST_HANDLER
#define bug WriteString
#define D(x) (x)
#else
#define D(x) ;
#endif /* TEST_HANDLER */

/*************************** Other Things *************************/


#define WORKBENCH


/*************************** ProtoTypes ***************************/

VOID SendPacketToDOS( struct DosPacket * );
VOID SetPacket( struct DosPacket *packet, ULONG res1, ULONG res2 );
VOID GetName( char *bcpl_str, char *newstr );
VOID ConvBSTRtoASTR( char *bstr, char *astr );
VOID ConvASTRtoBSTR( char *str );
char *ConvertStrToFileName( char * );
VOID CopyBSTR( char *bstr1, char *bstr2 );
void HandleDosMessage( struct DosPacket *, struct DeviceNode * );
void InsertLock( struct MyFileLock * );
void WriteString( char *str, ... );
void FillFIB( struct FileInfoBlock *Fib, struct Proc *proc, struct Proc *nextproc );
void InitPrivateList( void );
struct Proc *DupProc( struct Proc *proc );
struct Proc *FindParent( struct Proc *proc );
struct Proc *FindByTypeOrName( struct Proc *father, char *name, long dirtype );
struct Proc *FindEntry( struct MyFileLock *lck, char *name );
struct Proc *FindEntry_Proc( struct Proc *lckpr, char *name );
void FreeList( struct Proc *proc );
struct Proc *MakeList( struct Proc *father );
struct MyHandler *MakeFile( struct Proc * );
void DeleteAFile( struct Proc *, struct DosPacket *mypkt );

void act_FindInput( struct DosPacket *mypkt );
void act_End( struct DosPacket *mypkt );
void act_Read( struct DosPacket *mypkt );
void act_Seek( struct DosPacket *mypkt );
void act_Parent( struct DosPacket *mypkt, struct DeviceNode *mynode );
void act_Lock( struct DosPacket *mypkt, struct DeviceNode *mynode );
void act_UnLock( struct DosPacket *mypkt );
void act_DupLock( struct DosPacket *mypkt );
void act_Examine( struct DosPacket *mypkt );
void act_ExNext( struct DosPacket *mypkt );
void act_Delete( struct DosPacket *mypkt );
void act_Is_FileSystem( struct DosPacket *mypkt );
void act_Die( struct DosPacket *mypkt, struct DeviceNode *mynode );
void act_DiskInfo( struct DosPacket *mypkt, struct DeviceNode * );
void act_Info( struct DosPacket *mypkt, struct DeviceNode * );
void act_Default( struct DosPacket *mypkt );

/*************************** Defines *******************************/

#define AbsExecBase 4L
#define DOS_FALSE  0L
#define DOS_TRUE  -1L
#define RES2      mypkt->dp_Res2
#define toBCPL( a_ptr ) ( ( ULONG )( a_ptr ) >> 2 )

/**************** Constants and Definitions ************************/

struct MyFileLock
{
   BPTR mfl_Link;
   struct Proc *mfl_Proc;			/* ist pointer auf Proc-Struktur */
   LONG mfl_Access;
   struct MsgPort *mfl_Task;
   BPTR mfl_Volume;

/* own extensions */
   struct Proc *mfl_ProcDir;		/* ProcDir: Pointer auf ersten in Liste */
};

/* Reihenfolge muss identisch sein!!!! */
enum { DIR_MAIN= 1, DIR_PROCESS, DIR_PORT, DIR_SCREEN, DIR_WINDOW,
		 DIR_DEVICE, DIR_LIBRARY, DIR_INTERRUPT, DIR_RESOURCE };
enum { ENTRY_OF_MAIN = 129, ENTRY_OF_PROCESS, ENTRY_OF_PORT, ENTRY_OF_SCREEN, ENTRY_OF_WINDOW,
		 ENTRY_OF_DEVICE, ENTRY_OF_LIBRARY, ENTRY_OF_INTERRUPT, ENTRY_OF_RESOURCE };

struct Proc
{
	long proc_Type;		/* DIR_SCREEN, DIR_WINDOW, .., ENTRY_OF_SCREEN, .. */
	char proc_Name[108];	/* if DIR_...: nothing, if ENTRY_OF_... name of
									entry of proc_Type, used for read, lock, ... */
	char proc_Comment[80];
	void *proc_Next;		/* Next Entry */
	void *proc_Data;		/* ptr to data in ENTRY_OF_... */
	long proc_Flag;		/* no semantics defined for this! */
};

struct MyHandler
{
	char *mh_Mem;				
	LONG mh_Pos;
	LONG mh_Len;
};

struct PList
{
	struct PList *pl_Next;
	char pl_Name[108];
	long pl_Type;
};

/**************** Global Variables *********************************/

struct ExecBase *SysBase;
struct muBase *muBase;
struct IntuitionBase *IntuitionBase;
struct InfoData *IData;
struct DeviceList *VNode;
struct Process *ThisProc;
struct MsgPort *ThisPort;
struct DeviceNode *InfoNode;
BPTR HeaderLock = 0;
BPTR fh;
char DevName[40];

struct Proc ProcMain =
{
	DIR_MAIN,
	"PROC",
	"\0",
	0,
	0
};

struct PList *PListMain = 0;

/**************** Functions ****************************************/

/* MUST BE THE FIRST FUNCTION !!!! */

VOID __saveds ProcHandler( VOID ) 
{
	struct DosPacket *packet;
	struct DeviceNode *mynode;
	char convname[40];

	SysBase = *((struct ExecBase **) AbsExecBase); /* `open' exec.library */
	DOSBase = (struct DosLibrary *)OpenLibrary( "dos.library", 0 );
	IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 0 );
	muBase = (struct muBase *)OpenLibrary("multiuser.library", 39);


	if( !SysBase || !DOSBase || !IntuitionBase ) return;

	#ifdef TEST_HANDLER
		/*	fh = Open( "raw:0/11/640/89/Handler-Window", MODE_NEWFILE );
		 does not work, but I don't know why! */

		fh = *((BPTR *) 0);
		if( !fh ) return;		/* no window is open! */
	#endif

	ThisProc = (struct Process *)FindTask( 0 );
	ThisPort = &ThisProc->pr_MsgPort;

	packet = WaitPkt();
	mynode = BADDR( packet->dp_Arg3 );


	mynode->dn_Task = ThisPort;

	/* -> Wird auch auf der Workbench sichtbar :) */
#ifdef WORKBENCH
	mynode->dn_Type = DLT_VOLUME;
#endif


	CopyBSTR( BADDR( mynode->dn_Name ), convname );
	ConvBSTRtoASTR( convname, DevName );

	/* now allocate some mem, etc... */

	InitPrivateList();

	D(bug( "Name of dev: %s\n ", DevName ) );

	SetPacket( packet, DOS_TRUE, packet->dp_Res2 );
	SendPacketToDOS( packet );

	while( TRUE )
	{
   	if (packet = WaitPkt())
  	   	HandleDosMessage( packet, mynode );
	}
}

void HandleDosMessage( struct DosPacket *mypkt, struct DeviceNode *mynode )
{
	D(bug( "[1m%d:[0m ", mypkt->dp_Type ) );

	switch( mypkt->dp_Type )
	{
		case ACTION_FINDINPUT:
			act_FindInput( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_END:
			act_End( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_READ:
			act_Read( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_SEEK:
			act_Seek( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_PARENT:
			act_Parent( mypkt, mynode );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_LOCATE_OBJECT:
			act_Lock( mypkt, mynode );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_FREE_LOCK:
			act_UnLock( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_COPY_DIR:			/* = DupLock() */
			act_DupLock( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_EXAMINE_OBJECT:
			act_Examine( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_EXAMINE_NEXT:
			act_ExNext( mypkt );
			SendPacketToDOS( mypkt );
			break;

		case ACTION_DELETE_OBJECT:
			act_Delete( mypkt );
			SendPacketToDOS( mypkt );
			break;

      case ACTION_IS_FILESYSTEM:
			act_Is_FileSystem( mypkt );
			SendPacketToDOS( mypkt );
			break;

      case ACTION_DIE:
			act_Die( mypkt, mynode );
			SendPacketToDOS( mypkt );
			return;

		case ACTION_DISK_INFO:		/* wenn DLT_VOLUME an ist! */
			act_Info( mypkt, mynode );
			SendPacketToDOS( mypkt );
			break;

      case ACTION_INFO:
			act_Info( mypkt, mynode );
			SendPacketToDOS( mypkt );
			break;



      case ACTION_SET_PROTECT:		
			act_Default( mypkt );
			SendPacketToDOS( mypkt );
			/* 	braucht anscheinend die workbench! */
			break;

		default:
			act_Default( mypkt );
			SendPacketToDOS( mypkt );
			break;
	}
}





void act_FindInput( struct DosPacket *mypkt )
{
	char FName[120]; 
	struct FileHandle *fhandle;
	struct MyFileLock *lock;
	struct Proc *proc;
	char *name;

	fhandle = BADDR( mypkt->dp_Arg1 );
	lock = BADDR( mypkt->dp_Arg2 );
	name = BADDR( mypkt->dp_Arg3 );

	fhandle->fh_Port = (struct MsgPort *)DOS_FALSE;	/* error: or ThisPort ?? */
	GetName( name, FName );	 /* nach FName copieren */
	D(bug( "FIND_INPUT: |%s|\n", FName ) );

	if( proc = FindEntry( lock, FName ) )
	{
		if( proc->proc_Type & 128 )	/* must be a file! */
		{
			fhandle->fh_Arg1 = (long)MakeFile( proc );
			SetPacket( mypkt, DOS_TRUE, RES2 );
		}
		else
		{
			SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_WRONG_TYPE );
		}

		FreeVec( proc );
	}
	else
		SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_NOT_FOUND );

	D(bug( "  fh: $%x lck:$%x  arg1:$%x\n", fhandle, lock, fhandle->fh_Arg1 ) );
}


void act_End( struct DosPacket *mypkt )
{
	struct MyHandler *handle;

	handle = (struct MyHandler *)( mypkt->dp_Arg1 );

	D(bug( "END: $%x\n", handle ) );

	if( handle )
	{
		FreeVec( handle->mh_Mem );
		FreeVec( handle );
	}
	else
		SetPacket( mypkt, DOS_TRUE, RES2 );

	SetPacket( mypkt, DOS_TRUE, RES2 );
}


void act_Read( struct DosPacket *mypkt )
{
	struct MyHandler *handle;
	ULONG length, ptr;

	handle = (struct MyHandler *)( mypkt->dp_Arg1 );
	if( !handle )
	{
		SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_NOT_FOUND );
		return;
	}
	ptr = mypkt->dp_Arg2;
	length = mypkt->dp_Arg3;

	D(bug(  "READ: $%x len:%d ptr:$%x\n", handle, length, ptr ) );

	if( handle->mh_Pos < handle->mh_Len )	/* kann noch was gelesen werden! */
	{
		if( length > handle->mh_Len - handle->mh_Pos )
			length = handle->mh_Len - handle->mh_Pos;

		D(bug( "  did %d bytes\n", length ) );
		CopyMem( handle->mh_Mem + handle->mh_Pos, (APTR)ptr, length );
		handle->mh_Pos += length;
	}
	else length = 0;

	SetPacket( mypkt, length, RES2 );
}

void act_Seek( struct DosPacket *mypkt )
{
	struct MyHandler *handle;
	long pos, mode, rel, oldpos;

	handle = (struct MyHandler *)( mypkt->dp_Arg1 );
	if( !handle )
	{
		SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_NOT_FOUND );
		return;
	}
	rel = mypkt->dp_Arg2;
	mode = mypkt->dp_Arg3;
	oldpos = handle->mh_Pos;

	D(bug(  "SEEK: $%x rel:%d mode:%d\n", handle, rel, mode ) );

	switch( mode )
	{
		case OFFSET_CURRENT:
			pos = handle->mh_Pos;
			break;

		case OFFSET_BEGINNING:
			pos = 0;
			break;

		case OFFSET_END:
			pos = handle->mh_Len - 1;
			break;
	}

	pos += rel;

	if( pos < handle->mh_Len && pos >= 0 )
	{
		handle->mh_Pos = pos;
		SetPacket( mypkt, oldpos, RES2 );
	}
	else SetPacket( mypkt, DOS_FALSE, ERROR_SEEK_ERROR );
}

void act_Parent( struct DosPacket *mypkt, struct DeviceNode *mynode )
{
	struct MyFileLock *lock, *lck;
	struct Proc *proc;

	lck = BADDR( mypkt->dp_Arg1 );
	proc = (struct Proc *)lck->mfl_Proc;

	D(bug(  "PARENT: $%x, proc:$%x type:%d\n", lck, proc, proc->proc_Type ) );

	if( lck && proc->proc_Type != DIR_MAIN )
	{
		if( !( lock = AllocVec( sizeof( struct MyFileLock ), MEMF_CLEAR ) ) )
		{
			SetPacket( mypkt, DOS_FALSE, ERROR_NO_FREE_STORE );
  			return;
  		}
  		InsertLock( lock );

		lock->mfl_ProcDir = 0;
		lock->mfl_Proc    = FindParent( proc );
		lock->mfl_Access  = ACCESS_READ; 
  		lock->mfl_Task    = ThisPort;
	  	lock->mfl_Volume  = toBCPL( mynode );

		D(bug(  "  newl: $%x\n", lock ) );

		SetPacket( mypkt, toBCPL( lock ), RES2 );
	}
	else
	{
		RES2 = 0;
		SetPacket( mypkt, 0, RES2 );
	}
}


void act_Lock( struct DosPacket *mypkt, struct DeviceNode *mynode )
{
	char FName[120]; 
	struct MyFileLock *lock, *lck;
	char debugstr[258];
	char *name;
	ULONG mode;
	struct Proc *key;


	lck = BADDR( mypkt->dp_Arg1 );	/* Dir, where to search */
	name = BADDR( mypkt->dp_Arg2 );
	mode = mypkt->dp_Arg3;
	ConvBSTRtoASTR( name, debugstr );

	GetName( name, FName );

	D(bug( "LOCK: $%x |%s|->|%s|\n", lck, debugstr, FName ) );

	/* error:
	if( mode & ACCESS_WRITE )
	{
		SetPacket( mypkt, DOS_FALSE, ERROR_WRITE_PROTECTED );
		return;
	}
	*/

	if( key = FindEntry( lck, FName ) )
	{
		if( !( lock = AllocVec( sizeof( struct MyFileLock ), MEMF_CLEAR ) ) )
		{
			SetPacket( mypkt, DOS_FALSE, ERROR_NO_FREE_STORE );
			return;
		}

		D(bug(  "   Found: $%x, name:|%s|, type:%d\n", lock,
					((struct Proc *)key)->proc_Name, ((struct Proc *)key)->proc_Type ) );

  		InsertLock( lock );

		lock->mfl_Proc  = key;
		lock->mfl_Access = mode;		/* so?: must be ACCESS_READ */
  		lock->mfl_Task = ThisPort;
	  	lock->mfl_Volume = toBCPL( mynode );
	  	lock->mfl_ProcDir = (struct Proc *)0;
		SetPacket( mypkt, toBCPL( lock ), RES2 );
	}
	else
	{
		D(bug( "  lck FALSE, object not found\n" ) );
		SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_NOT_FOUND );
	}
}


void act_UnLock( struct DosPacket *mypkt )
{
	struct MyFileLock *lock, *lck = (struct MyFileLock *)4;
	struct Proc *proc;

	if( ( lock = BADDR( mypkt->dp_Arg1 ) ) )
	{
		D(bug( "FREE: l:$%x p:$%x pd:$%x\n", lock, lock->mfl_Proc, lock->mfl_ProcDir ) );
		/*	Hier muss der von FindByTypeOrName() gefundene
			Proc wieder gefreet werden	*/

		proc = ((struct Proc *)lock->mfl_Proc);
		D(bug( " freeing proc: $%x - t:%d\n", proc, proc->proc_Type ) );
		FreeVec( proc );


		/*	Hier muß, die proc-Liste aus lock->mfl_ProcDir
			gefreet werden! */

		if( lock->mfl_ProcDir )
		{
			D(bug( "  procdir: $%x\n", lock->mfl_ProcDir ) );
			FreeList( lock->mfl_ProcDir );
		}

		Forbid();
		if( (ULONG)BADDR( HeaderLock ) == (ULONG)lock )
		{
			HeaderLock = lock->mfl_Link;	/* DeleteLock ( Lock is Header ) */
		}
		else
		{
			lck = BADDR( HeaderLock );
			while( (ULONG)BADDR( lck->mfl_Link ) != (ULONG)lock )
			{
				lck = BADDR( lck->mfl_Link );
				if( !lck ) break;
			}
			if( lck )
				lck->mfl_Link = lock->mfl_Link; /* Neu verketten, lock auslassen */
		}
		FreeVec( lock );
		Permit();

		if( !lck )
			D(bug( "  lock:%x not found\n", lock ) );

		SetPacket( mypkt, DOS_TRUE, RES2 );
	}
	else
		SetPacket( mypkt, DOS_FALSE, ERROR_INVALID_LOCK );
}


void act_DupLock( struct DosPacket *mypkt )
{
	struct MyFileLock *lock, *lck;
	struct Proc *proc;

	if( ( lock = BADDR( mypkt->dp_Arg1 ) ) )
	{
		struct Proc *newproc;

		if( !( lck = AllocVec( sizeof( struct MyFileLock ), MEMF_CLEAR ) ) )
		{
			SetPacket( mypkt, DOS_FALSE, ERROR_NO_FREE_STORE );
			return;
		}
		CopyMem( lock, lck, sizeof( struct MyFileLock ) );

		proc = ((struct Proc *)lock->mfl_Proc);
		if( !( newproc = DupProc( proc ) ) )
		{
			SetPacket( mypkt, DOS_FALSE, ERROR_NO_FREE_STORE );
			return;
		}
		lck->mfl_Proc = newproc;

		D(bug( "DUPLOCK: oldl:$%x pr:$%x\n    prdir:$%x newl:$%x newpr:$%x\n", lock, lock->mfl_Proc, lock->mfl_ProcDir, lck, newproc ) );

		if( lck->mfl_ProcDir )
		{
		  	lck->mfl_ProcDir = 0;   /* Pointer auf ersten in Liste */
		}

  		InsertLock( lck );
		SetPacket( mypkt, toBCPL( lck ), RES2 );
	}
	else
		SetPacket( mypkt, DOS_FALSE, ERROR_INVALID_LOCK );
}


void act_Examine( struct DosPacket *mypkt )
{
	struct MyFileLock *lock;
	struct Proc *proc;
	struct FileInfoBlock *Fib;

	lock = BADDR( mypkt->dp_Arg1 );
	proc = (struct Proc *)lock->mfl_Proc;

	/* get FIB, fill with new things */
	Fib = (struct FileInfoBlock *)BADDR( mypkt->dp_Arg2 );
	FillFIB( Fib, proc, proc );

	D(bug( "EXAMINE: $%x |%s|\n", lock, Fib->fib_FileName ) );
	ConvASTRtoBSTR( Fib->fib_FileName );	/* i hate BCPL */
	ConvASTRtoBSTR( Fib->fib_Comment );

	if( !( proc->proc_Type & 128 ) )	/* DIR_xxx */
	{
		struct Proc *newproc;

		if( lock->mfl_ProcDir )					/* schon mal examiniert! */
			FreeList( lock->mfl_ProcDir );

		newproc = MakeList( proc );
		Fib->fib_EntryType = (long)newproc;
		lock->mfl_ProcDir = newproc;   		/* Pointer auf ersten in Liste */

		D(bug( "  DIR_xxx -> Liste allokiert!\n" ) );

		if( !newproc )		/* falls irgendwas schiefgeht, bzw. NOT_IMPL. */
		{
			D(bug( "  Kein newproc!\n" ) );

			SetPacket( mypkt, DOS_FALSE, ERROR_NOT_IMPLEMENTED );
			return;
		}

		/*
			Hier wurde jetzt eine Liste von Proc's (mit MakeList())
			erzeugt, abhängig von proc_Type.
			Diese Liste kann dann mit EX_NEXT durchgegangen
			werden.
			Dies hat den Vorteil, daß bei jedem neuen Dir-Read
			die Daten neu gelesen werden! 
			Außerdem wird diese neue proc-List in nach
			lock->mfl_ProcDir geschrieben, um zum freen wieder
			darauf zugreifen zu können!
		*/
	}
	else
	{
		;
		/* es wird ein File examiniert */
		/* aber FillFIB() macht eigentlich schon alles! */
		/* deshalb steht hier nichts! */
	}

	SetPacket( mypkt, DOS_TRUE, RES2 );
}


void act_ExNext( struct DosPacket *mypkt )
{
	struct MyFileLock *lock;
	struct Proc *proc, *procdir;
	struct FileInfoBlock *Fib;

	lock = BADDR( mypkt->dp_Arg1 );
	Fib = (struct FileInfoBlock *)BADDR( mypkt->dp_Arg2 );

	procdir = (struct Proc *)lock->mfl_Proc;
	proc = (struct Proc *)Fib->fib_EntryType;

	if( procdir->proc_Type & 128 )		/* not a directory!!! */
	{
		SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_WRONG_TYPE );
		return;		
	}

	if( !proc )
	{
		D(bug(  "EX_NEXT: NO_MORE_ENTRIES\n" ) );
		SetPacket( mypkt, DOS_FALSE, ERROR_NO_MORE_ENTRIES );
		return;
	}

	FillFIB( Fib, proc, proc->proc_Next );

	D(bug( "EX_NEXT: lock: $%x Fib:$%x |%s|, Proc:$%x Fl:%d\n", lock, Fib, Fib->fib_FileName, proc, proc->proc_Flag ) );

	ConvASTRtoBSTR( Fib->fib_FileName );
	ConvASTRtoBSTR( Fib->fib_Comment );

	SetPacket( mypkt, DOS_TRUE, RES2 );
}


void act_Delete( struct DosPacket *mypkt )
{
	char FName[120]; 
	struct MyFileLock *lock;
	struct Proc *proc;
	char *name;

	lock = BADDR( mypkt->dp_Arg1 );
	name = BADDR( mypkt->dp_Arg2 );
	GetName( name, FName );	 /* nach FName copieren */
	D(bug( "DELETE: lck:$%x |%s|\n", lock, FName ) );

	if( proc = FindEntry( lock, FName ) )
	{
		if( proc->proc_Type & 128 )	/* must be a file! */
		{
			SetPacket( mypkt, DOS_TRUE, RES2 );
			DeleteAFile( proc, mypkt );
		}
		else
		{
			SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_WRONG_TYPE );
		}

		FreeVec( proc );
	}
	else
		SetPacket( mypkt, DOS_FALSE, ERROR_OBJECT_NOT_FOUND );
}


void act_Is_FileSystem( struct DosPacket *mypkt )
{
	D(bug( " \n" ) );
	SetPacket( mypkt, DOS_TRUE, 0 );
}

void act_Die( struct DosPacket *mypkt, struct DeviceNode *mynode )
{
	mynode->dn_Task = 0;
	SetPacket( mypkt, DOS_TRUE, 0 );
}

void act_Info( struct DosPacket *mypkt, struct DeviceNode *mynode )
{
	struct MyFileLock *lock;
	struct InfoData *IData;

	lock = BADDR( mypkt->dp_Arg1 );
	IData = BADDR( mypkt->dp_Arg2 );

	D(bug( "(D)INFO: $%x $%x\n", lock, IData ) );

	if( IData && lock )
	{
		IData->id_NumSoftErrors = 0;
		IData->id_UnitNumber = 0;
		IData->id_DiskState = ID_VALIDATED;
		IData->id_NumBlocks = 4;
		IData->id_NumBlocksUsed = 4;
		IData->id_BytesPerBlock = 512;
		IData->id_DiskType = ID_DOS_DISK;
		IData->id_InUse = 0;
		IData->id_VolumeNode = toBCPL( mynode );
	}

	SetPacket( mypkt, DOS_TRUE, RES2 );
}

void act_Default( struct DosPacket *mypkt )
{
	D(bug( " not known\n" ) );
	SetPacket( mypkt, DOS_FALSE, ERROR_ACTION_NOT_KNOWN );
}




void InsertLock( struct MyFileLock *lock )
{
	Forbid();
	lock->mfl_Link = HeaderLock;
	HeaderLock = toBCPL( lock );	/* vorne einen Lock inserten */
	Permit();
}

void WriteString( char *str, ... )
{
	char strbuf[500];
	va_list VarArgs;

	va_start( VarArgs, str );
   vsprintf( strbuf, str, VarArgs );
   va_end( VarArgs ); 

   Write( fh, strbuf, strlen( strbuf ) );
}

void AppendData( char *ptr, char *str, ... )
{
	char strbuf[500];
	va_list VarArgs;

	va_start( VarArgs, str );
   vsprintf( strbuf, str, VarArgs );
   va_end( VarArgs ); 

	strcat( ptr, strbuf );
}

void FillFIB( struct FileInfoBlock *Fib, struct Proc *proc, struct Proc *nextproc )
{
	/* Fib muss nun abhänging von Daten-Typ und
		von proc gefüllt werden! */

	strcpy( Fib->fib_FileName, proc->proc_Name );
	strcpy( Fib->fib_Comment, proc->proc_Comment );

	if( proc->proc_Type & 128 )			/* file! */
	{
		Fib->fib_DirEntryType = -1;		/* means file */
		Fib->fib_Size = 1000;
		Fib->fib_NumBlocks = 2;
	}
	else											/* DIR_MAIN */
	{
		Fib->fib_DirEntryType = 1;			/* means dir */
		Fib->fib_Size = 0;
		Fib->fib_NumBlocks = 0;
	}

	Fib->fib_DiskKey = 0;
	Fib->fib_EntryType = (long)nextproc;	/* abuse it */
	Fib->fib_Protection = FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;	/* read only */
	Fib->fib_Date.ds_Days = 0;
	Fib->fib_Date.ds_Minute = 0;
	Fib->fib_Date.ds_Tick = 0;

	/* hier noch die muehe machen bei ENTRY_OF_PROCESS richtig zu setzen! */

	if( proc->proc_Type == ENTRY_OF_PROCESS && muBase )
	{
		Fib->fib_OwnerUID = muGetTaskOwner( (struct Task *)proc->proc_Data ) >> 16;
		Fib->fib_OwnerGID = muGetTaskOwner( (struct Task *)proc->proc_Data ) & 0xFFFF;
	}
	else
	{
		Fib->fib_OwnerUID = 0;
		Fib->fib_OwnerGID = 0;
	}
}

char *NextMain( void **ptr, struct Proc *father, long *type, long *flag )
{
	struct PList **proc = (struct PList **)ptr;
	static char name[108];

	if( *proc == 0 )
	{
		*proc = (struct PList *)PListMain;
	}
	else
	{
		if( !( *proc = (struct PList * )(*proc)->pl_Next ) )
			return (char *)0;
	}

	*type = (*proc)->pl_Type;					/* type auch zurückgeben! */
	strcpy( name, (*proc)->pl_Name );
	return name;
}

char *NextProcess( void **ptr, struct Proc *father, long *type, long *flag )
{
	struct Process **proc = (struct Process **)ptr;
	static char buf[20], name[108];

	if( *proc == 0 )
	{
		*proc = (struct Process * )SysBase->TaskWait.lh_Head;
	}
	else
	{
		*proc = (struct Process * )(*proc)->pr_Task.tc_Node.ln_Succ;
		if( !(*proc)->pr_Task.tc_Node.ln_Succ )
		{
			if( *flag == 0 )
			{
				*flag = 1;
				*proc = (struct Process * )SysBase->TaskReady.lh_Head;

				/* the line above doesn't work! */
				*proc = 0;
				return (char *)0;
			}
			else
			{
				*proc = 0;
				return (char *)0;
			}
		}
	}

	sprintf( buf, "%07x", *ptr );
	strcpy( name, buf ); 	/* Adresse vorneweg! */
	strcat( name, "_" );
	strcat( name, (*proc)->pr_Task.tc_Node.ln_Name );

	*type = ENTRY_OF_PROCESS;
	return name;
}

char *NextExec( void **ptr, struct Proc *father, long *type, long *flag )	/* will work for all ExecLists! */
{
	struct Library **lib = (struct Library **)ptr;
	static char name[20];

	if( *lib == 0 )
	{
		switch( father->proc_Type )
		{
			case DIR_LIBRARY:
				*lib = (struct Library * )SysBase->LibList.lh_Head;
				break;

			case DIR_INTERRUPT:
				*lib = (struct Library * )SysBase->IntrList.lh_Head;
				break;

			case DIR_PORT:
				*lib = (struct Library * )SysBase->PortList.lh_Head;
				break;

			case DIR_DEVICE:
				*lib = (struct Library * )SysBase->DeviceList.lh_Head;
				break;

			case DIR_RESOURCE:
				*lib = (struct Library * )SysBase->ResourceList.lh_Head;
				break;

			default:
				*lib = 0;
				break;
		}
	}
	else
	{
		*lib = (struct Library * )(*lib)->lib_Node.ln_Succ;
		if( !(*lib)->lib_Node.ln_Succ )
		{
			*lib = 0;
			return (char *)0;
		}
	}

	*type = father->proc_Type | 128;		/* make an entry of ... */

	if( !(*lib)->lib_Node.ln_Name )
	{
		sprintf( name, "%07x", *ptr );
		return name;
	}
	else
		return ConvertStrToFileName( (char *)(*lib)->lib_Node.ln_Name );
}

char *NextScreen( void **ptr, struct Proc *father, long *type, long *flag )
{
	struct Screen **scr = (struct Screen **)ptr;
/*	ULONG lckibase; */

	if( *scr == 0 )
	{
/*		if( lckibase = LockIBase( 0 ) ) { 
	the lock doesn't work :( */

			*scr = IntuitionBase->FirstScreen;

/*			UnlockIBase( lckibase ); } */
	}
	else
	{
		*scr = (*scr)->NextScreen;
	}

	if( !*scr ) return (char *)0;

	*type = DIR_WINDOW;
	return ConvertStrToFileName( (char *)(*scr)->Title );
}

char *NextWindow( void **ptr, struct Proc *father, long *type, long *flag )
{
	struct Screen *scr = (struct Screen *)father->proc_Data;
	struct Window **win = (struct Window **)ptr;
	static char buf[20], name[108];

	*type = ENTRY_OF_WINDOW;

	if( *flag == 0 )
	{
		*flag = 3;							/* means 1:next be window & 2:is screeninfo */
		*win = scr->FirstWindow;		/* because it will be used to find the belonging screen */

		strcpy( name, "ScreenInfo" );
		return name;
	}
	else if( *flag == 3 )
	{
		*flag = 1;							/* means this and next will be windows */
		*win = scr->FirstWindow;		/* Now show first window! */
	}
	else
	{
		*win = (*win)->NextWindow;
	}

	if( !*win ) return (char *)0;

	sprintf( buf, "%07x", *ptr );
	strcpy( name, buf ); 	/* Adresse vorneweg! */
	if( (*win)->Title )		/* nur wenn Titel da ist! */
	{
		/* error: hier string nach filenamen konvertieren!!! */

		sprintf( buf, "%.15s", ConvertStrToFileName( (*win)->Title ) );
		strcat( name, buf );
	}

	return (char *)name;
}

void FreeList( struct Proc *proc )
{
	struct Proc *dummy;

	while( proc )
	{
		dummy = proc->proc_Next;
		FreeVec( proc );
		proc = dummy;
	}
}

/* this is the Function GetNextFunctionByProc( struct Proc * )
	returning a function with void **,long as argument and returning
	a char * !!! */

char *( *GetNextFunctionByProc( struct Proc *father ) )( void **ptr, struct Proc *f, long *type, long *flag )
{
	switch( father->proc_Type )
	{
		case DIR_PROCESS:
			return NextProcess;
			
		case DIR_LIBRARY:
		case DIR_INTERRUPT:
		case DIR_DEVICE:
		case DIR_PORT:
		case DIR_RESOURCE:
			return NextExec;

		case DIR_MAIN:
			return NextMain;

		case DIR_SCREEN:
			return NextScreen;

		case DIR_WINDOW:
			return NextWindow;

		default:
			return 0;
	}
}


struct Proc *MakeProc( char *name, long type, void *ptr, long flag )
{
	struct Proc *proc = 0;

	if( !( proc = AllocVec( sizeof( struct Proc ), MEMF_CLEAR ) ) )
		return (struct Proc *)0;

	proc->proc_Type = type;
	proc->proc_Data = ptr;
	proc->proc_Flag = flag;

	strcpy( proc->proc_Name, name );

	/* so?: hier könnte bei Bedarf ein Kommentar gesetzt werden: 
		strcpy( proc->proc_Comment, "kommentar" );
   */

	return proc;
}

struct Proc *DupProc( struct Proc *proc )
{
	struct Proc *ret = 0;

	if( !proc ) proc = &ProcMain;		/* so?: should never be possible! */

	if( !( ret = AllocVec( sizeof( struct Proc ), MEMF_CLEAR ) ) )
		return (struct Proc *)0;

	CopyMem( proc, ret, sizeof( struct Proc ) );

	return ret;
}

struct Proc *MakeList( struct Proc *father )
{
	struct Proc *prochead = 0, *proc = 0;
	void *ptr = 0;
	char *name, *(*GetNextName)( void **, struct Proc *, long *, long * );
	long dtype, flag = 0;

	if( !(GetNextName = GetNextFunctionByProc( father )) )
		return (struct Proc *)0;

	while( name = (*GetNextName)( &ptr, father, &dtype, &flag ) )		/* in ptr wird Zeiger übergeben */
	{
		if( !( proc = MakeProc( name, dtype, ptr, flag ) ) ) break;

		if( !prochead )					/* setzen */
		{
			prochead = proc;
		}
		else
		{
			proc->proc_Next = prochead;
			prochead = proc;
		}
	}

	return prochead;
}

struct Proc *FindParent( struct Proc *proc )
{
	long type = proc->proc_Type;
	struct Proc *dummy, *pr;

	if( type & 128 )	/* ENTRY_OF_... */
	{
		type = type & (~128);

		if( type == DIR_WINDOW )
		{
			dummy = FindByTypeOrName( &ProcMain, "\0", DIR_SCREEN );
			pr = FindByTypeOrName( dummy, ((struct Window *)proc->proc_Data )->WScreen->Title, 0 );
			FreeVec( dummy );

			D(bug( "Parent(ENTRY): type:%d - found:$%x t:%d\n ", type, pr, pr->proc_Type ) );	
			return pr;
		}

		return FindByTypeOrName( &ProcMain, "\0", type );
	}
	else
	{
		if( type == DIR_WINDOW )
		{
			pr = FindByTypeOrName( &ProcMain, "\0", DIR_SCREEN );

			D(bug( "Parent(DIR): type:%d - found:$%x t:%d\n ", type, pr, pr->proc_Type ) );	
			return pr;
		}
		return DupProc( &ProcMain );
	}
}

struct Proc *FindByTypeOrName( struct Proc *father, char *name, long subtype )
{
	struct Proc *proc = 0;
	void *ptr = 0;
	char *gotname, *(*GetNextName)( void **, struct Proc *, long *, long * );
	long dtype, flag = 0;

	if( *name == '/' )		/* so?: eleganter bitte!!! */
	{
		return FindParent( father );
		/* so:?	return DupProc( &ProcMain );
			frueher war's so, is wohl nix mehr, da verschachtelte dirs!
		 */
	}

	if( !(GetNextName = GetNextFunctionByProc( father )) )
		return( struct Proc *)0;

	while( gotname = (*GetNextName)( &ptr, father, &dtype, &flag ) )
	{
		if( !*name )		/* Nicht by Name, sondern subtype */
		{
			if( dtype == subtype )
			{
				proc = MakeProc( gotname, dtype, ptr, flag );
				return proc;
			}
		}
		else
		{
			if( !stricmp( name, gotname ) )
			{
				proc = MakeProc( name, dtype, ptr, flag );
				return proc;
			}
		}
	}

	return (struct Proc *)0;
}

char *GetFullName( char *name )
{
	static char retname[108];
	long c = 0;

	for( c = 107; c >= 0; c-- ) retname[c] = 0;
	c = 0;

	while( *name == 0x01 ) name++;	/* HACK HACK: = schon abgearbeitet! */

	while( *name != '\0' )
	{
		retname[c++] = *name;
		*name++ = 0x01;			/* HACK: schon abgearbeitet! */
	}
	retname[c] = '\0';

	return retname;
}

char *GetPartName( char *name )
{
	static char retname[108];
	long c = 0;

	for( c = 107; c >= 0; c-- ) retname[c] = 0;
	c = 0;

	while( *name == 0x01 ) name++;	/* HACK HACK: = schon abgearbeitet! */

	if( *name == '/' )		/* so?: eins nach oben!!! */
	{
		retname[0] = '/';
		retname[1] = '\0';
		*name = 0x01;

		return retname;
	}

	while( *name != '\0' && *name != '/' )
	{
		retname[c++] = *name;
		*name++ = 0x01;			/* HACK: schon abgearbeitet! */
	}

	if( *name == '/' ) *name = 0x01;	/* nur bei /, sonst nicht!!! */
	retname[c] = '\0';

	return retname;
}

struct Proc *FindEntry( struct MyFileLock *lck, char *name )
{
	if( lck )
		return FindEntry_Proc( (struct Proc *)lck->mfl_Proc, name );
	else
		return FindEntry_Proc( (struct Proc *)0, name );
}

struct Proc *FindEntry_Proc( struct Proc *lckpr, char *name )
{
	struct Proc *proc = 0;
	struct Proc *retkey = 0;
	char partname[108];

	if( name && *name == '\0' ) name = 0;		/* einfacher abzufragen! */

	if( !lckpr )		/* nichts uebergeben -> DIR_MAIN suchen! */
	{
		if( !name || *name == '\0' )
		{
			retkey = DupProc( &ProcMain );	/* reproduce proc! */
			return retkey;
		}
	}

	if( lckpr && !name )		/* nochmals DIR selbst zurückgeben!!! */
	{
		retkey = DupProc( lckpr );		/* reproduce lckpr! */
		return retkey;
	}

		/* je nach proc_Type  */

		/* neuen proc allocieren für Objekt            */
		/* in proc_Type dann ENTRY_... schreiben!      */
		/* wird alles in FindByTypeOrName() erledigt! */

	if( !lckpr )	/* main-dir! */
	{
		lckpr = &ProcMain;
	}

	strcpy( partname, GetPartName( name ) );
	D(bug( "  FindEntry:part: |%s| of |%s|\n", partname, name ) );
	if( retkey = FindByTypeOrName( lckpr, partname, 0 ) )
	{
		strcpy( partname, GetFullName( name ) );
		if( *partname )	/* still sth. remaining */
		{
			D(bug( "  FindEntry:Remaining |%s|\n", partname ) );
			proc = retkey;
			retkey = FindEntry_Proc( proc, partname );
			FreeVec( proc );
		}
	}

	if( retkey )
	{
		D(bug( "  FindByTypeOrName(): $%x >%s<\n", retkey, retkey->proc_Name ) );;
	}
	else
	{
		D(bug( "  FindByTypeOrName(): nothing found\n" ) );;
	}

	return retkey;
}

struct MyHandler *MakeFile( struct Proc *proc )
{
	struct muUserInfo *uinfo;
	struct MyHandler *mh;
	struct Process *p;
	struct Library *l;
	struct Interrupt *i;
	struct MsgPort *mp;
	struct Screen *scr;
	struct Window *win;
	struct PList *pl;
	ULONG owner;
	char *ptr;

	if( !( ptr = AllocVec( 4096, MEMF_CLEAR ) ) )
		return (struct MyHandler *)0;

	if( !( mh = AllocVec( sizeof( struct MyHandler ), MEMF_CLEAR ) ) )
	{
		FreeVec( ptr );
		return (struct MyHandler *)0;
	}

	switch( proc->proc_Type )
	{
		case ENTRY_OF_PROCESS:
			p = (struct Process *)proc->proc_Data;
			AppendData( ptr, "%s: %s at $%x\n", p->pr_Task.tc_Node.ln_Type == NT_TASK ? "Task" : "Process", p->pr_Task.tc_Node.ln_Name, p );
			AppendData( ptr, "Prio: %d\n", p->pr_Task.tc_Node.ln_Pri );
			if( muBase )
			{
				if( uinfo = muAllocUserInfo() )
				{
					owner = muGetTaskOwner( (struct Task *)p ) >> 16;
					if( owner )
					{
						uinfo->uid = owner;
						muGetUserInfo( uinfo, muKeyType_uid );
						AppendData( ptr, "Owner: %s (%d)\n", uinfo->UserName, owner );
					}
					else
						AppendData( ptr, "Owner: nobody\n" );

					muFreeUserInfo(uinfo);
				}
			}
			AppendData( ptr, "Stack    : $%x\n", p->pr_Task.tc_SPReg );
			AppendData( ptr, "Stacksize: $%x\n", (ULONG)p->pr_Task.tc_SPUpper - (ULONG)p->pr_Task.tc_SPLower );
			AppendData( ptr, "Signals : $%x\n", p->pr_Task.tc_SigWait );
			AppendData( ptr, "Received: $%x\n", p->pr_Task.tc_SigRecvd );
			if( p->pr_Task.tc_Node.ln_Type == NT_PROCESS )
			{
				AppendData( ptr, "CurrentDir: $%x\n", BADDR( p->pr_CurrentDir ) );
				AppendData( ptr, "CIS: $%x\n", BADDR( p->pr_CIS ) );
				AppendData( ptr, "COS: $%x\n", BADDR( p->pr_COS ) );
				AppendData( ptr, "ConsoleTask: $%x\n", p->pr_ConsoleTask );
				AppendData( ptr, "FileSystemTask: $%x\n", p->pr_FileSystemTask );
				AppendData( ptr, "Window: $%x\n", p->pr_WindowPtr );
			}
			break;

		case ENTRY_OF_LIBRARY:
		case ENTRY_OF_DEVICE:
		case ENTRY_OF_RESOURCE:
			l = (struct Library *)proc->proc_Data;
			AppendData( ptr, "%s: %s at $%x\n",
				proc->proc_Type == ENTRY_OF_LIBRARY ? "Library" : 
					(proc->proc_Type == ENTRY_OF_DEVICE ? "Device" : "Resource"),
				l->lib_Node.ln_Name, l );
			AppendData( ptr, "Priori.: %d\n", l->lib_Node.ln_Pri );
			AppendData( ptr, "Version: %d.%d\n", l->lib_Version, l->lib_Revision );
			AppendData( ptr, "OpenCnt: %d\n", l->lib_OpenCnt );
			AppendData( ptr, "NegSize: %d\n", l->lib_NegSize );
			AppendData( ptr, "PosSize: %d\n", l->lib_PosSize );
			break;

		case ENTRY_OF_INTERRUPT:
			i = (struct Interrupt *)proc->proc_Data;
			AppendData( ptr, "Interrupt: %s at $%x\n", i->is_Node.ln_Name, i );
			break;

		case ENTRY_OF_PORT:
			{
				char *mpflagstr[] = { "signal", "softint", "ignore", "action" };

				mp = (struct MsgPort *)proc->proc_Data;
				AppendData( ptr, "Port: %s at $%x\n\n", mp->mp_Node.ln_Name, mp );

				AppendData( ptr, "Flags  : %s\n", mpflagstr[mp->mp_Flags] );
				AppendData( ptr, "SigBit : %d\n", mp->mp_SigBit );
				if( mp->mp_Flags == PA_SIGNAL	)
					AppendData( ptr, "SigTask: %s at $%x\n", ((struct Task *)mp->mp_SigTask)->tc_Node.ln_Name, mp->mp_SigTask );
				else if( mp->mp_Flags == PA_SOFTINT	)
					AppendData( ptr, "SoftInt: $%x\n", mp->mp_SigTask );
			}
			break;

		case ENTRY_OF_SCREEN:
			scr = (struct Screen *)proc->proc_Data;
			AppendData( ptr, "You found a bug in Proc-Handler!!\nIt is not possible to get here :(\n" );
			AppendData( ptr, "Screen: \"%s\" at $%x\n", scr->Title, scr );
			break;

		case ENTRY_OF_WINDOW:
			win = (struct Window *)proc->proc_Data;
			if( proc->proc_Flag & 2 )	/* This here is the ScreenInfo-File in the DIR_WINDOW! */
			{
				scr = win->WScreen;
				AppendData( ptr, "Screen: \"%s\" at $%x\n\n", scr->Title ? (char *)scr->Title : (char *)"<no name>", scr );

				AppendData( ptr, "Left : %3d  Top...: %3d\n", scr->LeftEdge, scr->TopEdge );
				AppendData( ptr, "Width: %3d  Height: %3d\n\n", scr->Width, scr->Height );

				AppendData( ptr, "WBorLeft : %3d  WBorTop...: %3d\n", scr->WBorLeft, scr->WBorTop );
				AppendData( ptr, "WBorRight: %3d  WBorBottom: %3d\n\n", scr->WBorRight, scr->WBorBottom );

				AppendData( ptr, "BarHeight: %3d  BarVBorder: %3d BarHBorder: %3d\n", scr->BarHeight, scr->BarVBorder, scr->BarHBorder );
				AppendData( ptr, "MenuVBorder: %3d  MenuHBorder: %3d\n\n", scr->MenuVBorder, scr->MenuHBorder );

				AppendData( ptr, "ViewPort: $%x\n", &scr->ViewPort );
				AppendData( ptr, "          DWidth..: %3d  DHeight : %3d\n", scr->ViewPort.DWidth, scr->ViewPort.DHeight );
				AppendData( ptr, "          DxOffset: %3d  DyOffset: %3d\n", scr->ViewPort.DxOffset, scr->ViewPort.DyOffset );
				AppendData( ptr, "          Modes...: $%x\n\n", scr->ViewPort.Modes );

				AppendData( ptr, "RastPort: $%x\n", &scr->RastPort );
				AppendData( ptr, "          BitMap: $%x\n\n", scr->RastPort.BitMap );

				AppendData( ptr, "Font : %s/%d\n", scr->Font->ta_Name, scr->Font->ta_YSize );
				AppendData( ptr, "Flags: $%x\n", scr->Flags );
			}
			else
			{
				AppendData( ptr, "Window: \"%s\"", win->Title ? (char *)win->Title : (char *)"<no name>" );

				AppendData( ptr, " at $%x\n\n", win );
				AppendData( ptr, "Left : %3d  Top...: %3d\n", win->LeftEdge, win->TopEdge );
				AppendData( ptr, "Width: %3d  Height: %3d\n\n", win->Width, win->Height );

				AppendData( ptr, "MinWidth: %3d  MinHeight: %3d\n", win->MinWidth, win->MinHeight );
				AppendData( ptr, "MaxWidth: %3d  MaxHeight: %3d\n\n", win->MaxWidth, win->MaxHeight );

				AppendData( ptr, "BorderLeft : %3d  BorderTop...: %3d\n", win->BorderLeft, win->BorderTop );
				AppendData( ptr, "BorderRight: %3d  BorderBottom: %3d\n\n", win->BorderRight, win->BorderBottom );

				AppendData( ptr, "DetailPen: %d  BlockPen: %d\n\n", win->DetailPen, win->BlockPen );

				AppendData( ptr, "Flags : $%x\n", win->Flags );
				AppendData( ptr, "IDCMP : $%x\n", win->IDCMPFlags );
			}
			break;

		case ENTRY_OF_MAIN:
			pl = (struct PList *)proc->proc_Data;
			if( !stricmp( pl->pl_Name, "Sysinfo" ) )
			{
				static char *cpustr[] = { "68000", "68010", "68020", "68030", "68040" };
				static char *fpustr[] = { "<none>", "68881", "68882", "68040" };
				int cpuc = 0, fpuc = 0;

				if( SysBase->AttnFlags & AFF_68010 ) cpuc = 1;
				if( SysBase->AttnFlags & AFF_68020 ) cpuc = 2;
				if( SysBase->AttnFlags & AFF_68030 ) cpuc = 3;
				if( SysBase->AttnFlags & AFF_68040 ) cpuc = 4;

				if( SysBase->AttnFlags & AFF_68881 ) fpuc = 1;
				if( SysBase->AttnFlags & AFF_68882 ) fpuc = 2;
				if( SysBase->AttnFlags & AFF_FPU40 ) fpuc = 3;

				AppendData( ptr, "Sysinfo\n\n" );
				AppendData( ptr, "Kickstart V%d.\n", SysBase->SoftVer );
				AppendData( ptr, "CPU: %s  FPU: %s\n", cpustr[cpuc], fpustr[fpuc] );
				AppendData( ptr, "Memory: ---\n" );
				AppendData( ptr, "DMA Chip: ---\n" );
				AppendData( ptr, "Graphic Chip: ---\n" );
			}
			else
				AppendData( ptr, "Not supported yet!\n" );
			break;

		default:
			AppendData( ptr, "No data available!\n" );
			break;
	}

	mh->mh_Mem = ptr;
	mh->mh_Len = strlen( ptr );
	mh->mh_Pos = 0;

	return mh;
}

void DeleteAFile( struct Proc *proc, struct DosPacket *mypkt )
{
	switch( proc->proc_Type )
	{
		case ENTRY_OF_WINDOW:
			if( proc->proc_Data )
			{
				if( proc->proc_Flag & 2 )
				{
					struct Screen *scr;

					scr = ((struct Window *)proc->proc_Data)->WScreen;
					if( scr->FirstWindow )
					{
						SetPacket( mypkt, DOS_FALSE, ERROR_DELETE_PROTECTED );
					}
					else
					{
						if( !CloseScreen( scr ) )		/* This is V36+ */
						{
							SetPacket( mypkt, DOS_FALSE, ERROR_DELETE_PROTECTED );
						}
					}
				}
				else 	/* Window zumachen! */
				{
					struct MsgPort *port;
					struct Window *win = (struct Window *)proc->proc_Data;
					struct Requester *req;

					ModifyIDCMP(win, NULL);

					ClearDMRequest(win);
					ClearMenuStrip(win);
					ClearPointer(win);

					while( req = win->FirstRequest )
						EndRequest(req, win);

					CloseWindow( win );
				}
			}
			break;

		case ENTRY_OF_PROCESS:		/* do ONLY use, IF YOU KNOW WHAT YOU ARE DOING */
			if( proc->proc_Data )
			{
				struct Task *t = (struct Task *)proc->proc_Data;

				RemTask( t );
			}
			break;

		default:
			break;
	}
}

void AddEntryToPrivateList( long type, char *name )
{
	struct PList *pl = 0;
	
	pl = AllocVec( sizeof( struct PList ), MEMF_CLEAR );
	if( !pl ) return;

	strcpy( pl->pl_Name, name );
	pl->pl_Type = type;
	pl->pl_Next = PListMain;

	Forbid();
	PListMain = pl;
	Permit();
}

void InitPrivateList( void )
{
	strcpy( ProcMain.proc_Name, DevName );

	AddEntryToPrivateList( ENTRY_OF_MAIN, "Sysinfo" );	/* Last First */
/*	AddEntryToPrivateList( DIR_WINDOW, "Window" ); */
/* so?: die Windows sind nun Dirs in Screen :)    */
	AddEntryToPrivateList( DIR_SCREEN, "Screen" );

	AddEntryToPrivateList( DIR_RESOURCE, "Resource" );
	AddEntryToPrivateList( DIR_DEVICE, "Device" );
	AddEntryToPrivateList( DIR_LIBRARY, "Library" );

	AddEntryToPrivateList( DIR_PORT, "Port" );
/*	AddEntryToPrivateList( DIR_INTERRUPT, "Interrupt" ); */
	AddEntryToPrivateList( DIR_PROCESS, "Process" );
}

VOID SendPacketToDOS( struct DosPacket *packet )
{
	struct Message *mess;
	struct MsgPort *replyport;
	struct Process *myproc;

	replyport = packet->dp_Port;
	mess		= packet->dp_Link;
	myproc	 = (struct Process *)FindTask( 0 );

	packet->dp_Port		 = ThisPort;
	mess->mn_Node.ln_Name = ( char * )packet;
	mess->mn_Node.ln_Succ = NULL;
	mess->mn_Node.ln_Pred = NULL;

	PutMsg( replyport, mess );
}

VOID SetPacket( struct DosPacket *packet, ULONG res1, ULONG res2 )
{
	packet->dp_Res1 = res1;
	packet->dp_Res2 = res2;
}

VOID ConvASTRtoBSTR( char *str )
{
	LONG f;
	char *to = ( str + 1 );

	if( *str == (char)0 ) return;

	for( f = strlen( str ); f >= 0; f-- )
		to[ f ] = str[ f ];
	*str = strlen( str + 1 );
}

VOID ConvBSTRtoASTR( char *bstr, char *astr )
{
	UBYTE len;

	len = *bstr++;

	for( ; len && *bstr; len-- )
		*astr++ = *bstr++;
	*astr = '\0';
}

VOID CopyBSTR( char *bstr1, char *bstr2 )
{
	UBYTE len;
	len = *bstr1 + 1;
	for( ; len; len-- )
		*bstr2++ = *bstr1++;
}

char *ConvertStrToFileName( char *str )
{
	static char filename[100];
	int i = 0;

	while( i < 100 )
	{
		switch( str[i] )
		{
			case ' ':					/* space to underscore */
				filename[i] = '_';
				break;

			case ':':
				filename[i] = '.';
				break;

			case '?':
				filename[i] = '.';
				break;

			case '#':
				filename[i] = '.';
				break;

			case '*':
				filename[i] = '.';
				break;

			default:
				filename[i] = str[i];
				break;
		}

		if( filename[i] == '\0' ) break;

		i++;
	}

	return filename;
}

VOID GetName( char *bcpl_str, char *newstr )
{
	UBYTE len1, len2;
	char *tester = bcpl_str + 1;

	len1 = len2 = *bcpl_str++;

	for(; len1 && *tester; len1-- )
	{
		if( *tester++ == ':' )
		{
			len2--;
			while( *bcpl_str++ != ':' ) len2--;
			break;
		}
	}

	for( ; len2 && *bcpl_str; len2-- )
		*newstr++ = *bcpl_str++;

	*newstr = '\0';
}
