/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1990 by MXM
 *
 *	Name .....: Null-Handler.c
 *	Created ..: Saturday 31-Mar-90 13:47
 *	Revision .: 0
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	15-Apr-90       Olsen           Ported to Aztec 'C' 5.0
 *	07-Jan-90       Olsen           Created this file!
 *
 *	Skeleton    handler    code   by   Phillip   Lindsay   (C)   1986
 *	Commodore-Amiga,  Inc.  You may freely distribute this source and
 *	use  it for Amiga Development, as long as the Copyright notice is
 *	left intact.
 *
 ****************************************************************************
 *
 *	This  is  an  example how a 'real' NIL:  handler could look like.
 *	It  is very loosely based on the 'my-handler' source code written
 *	by Phillip Lindsay.  Since I have no access to the source code of
 *	the  original  Null-Handler  I  rewrote it using Lattice 'C' 5.04
 *	which  resulted  in  a very small executable file (actually about
 *	568 bytes long, about 340 bytes less than the original handler).
 *	       Three weeks later I thought "well, why not try to bring it
 *	back to Aztec 'C'?".  And that's what I did.  I can't believe it,
 *	Aztec 'C' 5.0 does a brilliant job on the program:  it's actually
 *	124 bytes smaller than the Lattice version.
 *
 * $Revision Header ********************************************************/

	/* Main includes. */

#include <libraries/filehandler.h>
#include <libraries/dosextens.h>
#include <exec/execbase.h>

#include <pragma/exec_lib.h>

/*#include <functions.h>*/

	/* Prototypes for this module. */

LONG			HandlerEntry(VOID);
VOID			ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc);
struct DosPacket *	WaitPacket(struct Process *HandlerProc);

	/* Some magic pragmas. */

#pragma regcall(ReturnPacket(a0,d0,d1,a1))
#pragma regcall(WaitPacket(a0))

	/* Global pointer to ExecBase. */

struct ExecBase		*SysBase;

	/* HandlerEntry():
	 *
	 *	The entry point for this handler.
	 */

LONG
HandlerEntry()
{
	struct Process *HandlerProc;

		/* Set the ExecBase pointer. */

	SysBase = (struct ExecBase *)(*(LONG *)4);

		/* Get a pointer to the process structure of the
		 * handler.
		 */

	HandlerProc = (struct Process *)SysBase -> ThisTask;

		/* If not called from CLI (you shouldn't do that)
		 * we'll start up as a DOS-handler.
		 */

	if(!HandlerProc -> pr_CLI)
	{
		struct DosPacket	*NullPacket;
		struct DeviceNode	*NullNode;

			/* Wait for startup packet (we aren't a
			 * BCPL module).
			 */

		NullPacket = WaitPacket(HandlerProc);

			/* Get pointer to handler device node. */

		NullNode = (struct DeviceNode *)BADDR(NullPacket -> dp_Arg3);

			/* Install handler task ID -> we're running. */

		NullNode -> dn_Task = &HandlerProc -> pr_MsgPort;

			/* Return the startup packet to DOS. */

		ReturnPacket(NullPacket,DOSTRUE,NullPacket -> dp_Res2,HandlerProc);

			/* Run forever - or until somebody lets us die. */

		for(;;)
		{
				/* Wait for a packet. */

			NullPacket = WaitPacket(HandlerProc);

				/* Check the type. */

			switch(NullPacket -> dp_Type)
			{
				case ACTION_FINDINPUT:
				case ACTION_FINDOUTPUT:
				case ACTION_FINDUPDATE:	
				case ACTION_END:	ReturnPacket(NullPacket,DOSTRUE,0,HandlerProc);
							break;

				case ACTION_WRITE:	ReturnPacket(NullPacket,NullPacket -> dp_Arg3,0,HandlerProc);
							break;

				case ACTION_READ:	ReturnPacket(NullPacket,0,0,HandlerProc);
							break;

				case ACTION_DIE:	ReturnPacket(NullPacket,DOSTRUE,0,HandlerProc);
							goto FallOff;

				default:		ReturnPacket(NullPacket,DOSFALSE,ERROR_ACTION_NOT_KNOWN,HandlerProc);
							break;
			}
		}

			/* Okay, we're done, zero the task ID field
			 * and fall through.
			 */
	
FallOff:	NullNode -> dn_Task = NULL;
	}
}

	/* ReturnPacket():
	 *
	 *	Returns a packet to DOS.
	 */

VOID
ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc)
{
	struct MsgPort *ReplyPort;

		/* Remember origin port. */

	ReplyPort = Packet -> dp_Port;

		/* Fill in the result fields. */

	Packet -> dp_Res1 = Res1;
	Packet -> dp_Res2 = Res2;

		/* Install our task ID. */

	Packet -> dp_Port = &HandlerProc -> pr_MsgPort;

		/* Initialize the packet node head. */

	Packet -> dp_Link -> mn_Node . ln_Name	= (char *)Packet;
	Packet -> dp_Link -> mn_Node . ln_Succ	= NULL;
	Packet -> dp_Link -> mn_Node . ln_Pred	= NULL;

		/* Return the packet to the sender. */

	PutMsg(ReplyPort,Packet -> dp_Link);
}

	/* WaitPacket():
	 *
	 *	Wait for a DOS packet.
	 */

struct DosPacket *
WaitPacket(struct Process *HandlerProc)
{
	struct Message *DOSMsg;

		/* Wait at the port... */

	WaitPort(&HandlerProc -> pr_MsgPort);

		/* Get the packet. */

	DOSMsg = (struct Message *)GetMsg(&HandlerProc -> pr_MsgPort);

		/* Return a pointer to its head. */

	return((struct DosPacket *)DOSMsg -> mn_Node . ln_Name);
}
