#pragma libcall TrackBase TrackItem 1E 18003
#pragma libcall TrackBase FreeTrackedItem 24 801
#pragma libcall TrackBase FreeTrackList 2A 0
#pragma libcall TrackBase AddProcess 30 0
#pragma libcall TrackBase RemoveProcess 36 0
#pragma libcall TrackBase SetTrap 3C 801
#pragma libcall TrackBase GetTrap 42 0
/*pragma libcall TrackBase Printf 48 9802*/
/*pragma libcall TrackBase SPrintf 4E 98A03*/
/*pragma libcall TrackBase FPrintf 54 98A03*/
#pragma libcall TrackBase MemAlloc 5A 1002
#pragma libcall TrackBase MemFree 60 901
#pragma libcall TrackBase CreatePort 66 0802
#pragma libcall TrackBase DeletePort 6C 801
#pragma libcall TrackBase CreateExtIO 72 0802
#pragma libcall TrackBase DeleteExtIO 78 901
#pragma libcall TrackBase TOpenWindow 7E 801
#pragma libcall TrackBase TOpenScreen 84 801
#pragma libcall TrackBase TMemAlloc 8A 1002
#pragma libcall TrackBase TCreatePort 90 0802
#pragma libcall TrackBase TCreateExtIO 96 0802
#pragma libcall TrackBase TOpenDevice 9C 190804
#pragma libcall TrackBase TSetDMRequest A2 9802
#pragma libcall TrackBase TSetMenuStrip A8 9802
#pragma libcall TrackBase TOpenLibrary AE 0902
#pragma libcall TrackBase TOpen B4 2102
#pragma libcall TrackBase Reads BA 32103
#pragma libcall TrackBase OnSignal C0 8002
#pragma libcall TrackBase CreatePacket C6 801
#pragma libcall TrackBase DeletePacket CC 0802
#pragma libcall TrackBase SendPacket D2 8902
#pragma libcall TrackBase WaitPacket D8 901
#pragma libcall TrackBase DoPacket DE 8902
#pragma libcall TrackBase TCreatePacket E4 801
#pragma libcall TrackBase MakeBStr EA 801
#pragma libcall TrackBase CheckPacket F0 901
#pragma libcall TrackBase NewList F6 801
#pragma libcall TrackBase SetJmp FC 801
#pragma libcall TrackBase LongJmp 102 801
#pragma libcall TrackBase ChkBound 108 12003
#pragma libcall TrackBase ChkRange 10E 12003
#pragma libcall TrackBase AbsChk 114 1002
#pragma libcall TrackBase AbsChkWord 11A 1002
#pragma libcall TrackBase ExceptInit 120 801
#pragma libcall TrackBase ExceptEnter 126 801
#pragma libcall TrackBase ExceptLeave 12C 0
#pragma libcall TrackBase ExceptCall 132 001
#pragma libcall TrackBase ExceptRaise 138 A002
#pragma libcall TrackBase ExceptCode 13E 0
#pragma libcall TrackBase TrapMsg 144 001
#pragma libcall TrackBase TLock 14A 2102
#pragma libcall TrackBase Strchr 150 1802
#pragma libcall TrackBase Strcat 156 9802
#pragma libcall TrackBase Atol 15C 801

/*
 *
 * Tracking routines.
 *
 */

#include "exec/types.h"
#include <exec/lists.h>
#include <exec/nodes.h>
#include "exec/libraries.h"
#include "libraries/dos.h"
#include "intuition/intuition.h"

#include <setjmp.h>

/*
 * Exception system.
 *
 * This handler is special because it requires only one support routine, and
 * you write it! And it uses only AmigaDos List functions.
 * 
 * Usage :
 *
 * 1) In the HIGHEST routine that uses the exceptions, (often main()), place
 *    the line 'EINIT(handlername) ;' to initialise the exception handler.
 *    OR, you may use 'EHANDLERINIT()' to initialise the default handler
 *    found in d.lib
 *
 * 2) At the beginning of the code to be protected, place the word
 *    PROTECTED to define the start of the section. 
 *
 * 3) Place the protected code.
 *
 * 4) Place the work 'EXCEPTION' on a line of its own, to declare the
 *    beginning of the code to jump to in case of an exception.
 *
 * 5) Place the exception code. Within the exception code, the reason for the
 *    exception can be found via the function 'LASTEXCEPTION()' which returns
 *    a long.
 * 
 * 6) At the end of the exception code, place the word NORMAL. This
 *    terminates the exception code. Any code after this is executed whether
 *    and exception occurred or not. NOTE that it is not legal to 'return'
 *    from within the PROTECTed or EXCEPTION zone. NOTE that after a 'NORMAL'
 *    any exception will cause the code to jump to an exception handler at
 *    a higher level (eg, the handler code of the calling function.)
 *
 * To cause an exception to jump to the exception code (or from the
 * exception code to the callers exception code), use the 'RAISEEXCEPTION'
 * macro. NOTE that this acts differently depending on whether you are in 
 * a protected zone or a exception zone.
 *
 * LASTLY, you must make an exception handler. This is an example
 *
 * void * myexception(void) {
 *    long *codes = GetTrap() ;			GetTrap() is MY code to get the
 *                                      reason for the exception. 
 *    CALLEXCEPTION(codes[0]) ;			Go to the Exception handler.
 *    }                                 This macro also sets the CONTEXT
 *                						to EXCEPTIONZONE.
 */ 		


void __stdargs _DefaultEHandler(void) ;

#define EINIT(handler)  ExceptInit(handler)
#define EHANDLERINIT()  EINIT(_DefaultEHandler)

#define PROTECTED  if (!ExceptEnter(0)) {
#define PROTECT(x) if (!ExceptEnter(x)) {
#define EXCEPTION     } else {
#define NORMAL      } ExceptLeave() ;
/* #define CALLEXCEPTION(code) ExceptCall(code) */
#define RAISENAMEDEXCEPTION(code,name) ExceptRaise(code,name)
#define RAISEEXCEPTION(code) ExceptRaise(code,0L)
#define LASTEXCEPTION() ExceptCode()
#define  TRACK_VERSION	(5)

/*
 * Possible exceptions codes returned by 'GetTrap' after an exception.
 *
 * NOTE: EX_* are processor exception codes, EXT_* are extended codes...
 */
typedef enum { EX_NONE, EX_TRAP, EX_BUS_ERROR, EX_ADDRESS_ERROR, EX_ILLEGAL,
               EX_DIVIDE_BY_ZERO, EX_CHK, EX_TRAPV, EX_PRIVILEDGE, EX_TRACE,
               EX_LINE_1010, EX_LINE_1111, EX_MC68000,
	       EXT_ASSERT_FAIL
	       } EX_CODES ;

typedef enum { PROTECTZONE, EXCEPTIONZONE } context ;

typedef struct {
   struct MinNode Next ;
   char *EI_name ;
   jmp_buf EI_Save ;
   unsigned long EI_Code ;
   unsigned char EI_Context ;
   } EInstance ;

struct TrackNode {
    struct TrackNode *tn_Next;
    long tn_Item;
    void (*tn_drop)(long item, void *func, long param) ;
    long tn_param;
    } ;

struct TrapInfo {
    long  ti_TrapNO;
    long  ti_TrapPC;
    long  ti_TrapMsg;
    } ;

struct ProcessList {
    struct ProcessList *pl_Next;
    long        pl_TaskID;
    struct TrackNode *pl_List;
    long        pl_loaderdb;
    long        pl_TrapCode;
    long        pl_TrapData;
    long        pl_Handler;
    long        pl_ExceptCode;
    long        pl_ExceptData;
	struct	TrapInfo pl_TrapInfo;
    long        pl_ExceptMask;
    long        pl_ExceptVec;
	struct		MinList pl_EHandler;		/* Exception handler list */
    } ;

struct TrackBase {
    struct Library tb_Lib ;
    ULONG    tb_SegList;
    ULONG    tb_Flags;
    APTR     tb_ExecBase;
    APTR     tb_Anchor;
    struct Library *tb_DOSBase;
    struct Library *tb_IntuitionBase;
    struct Library *tb_GfxBase;
    struct Library *tb_LayersBase;
    LONG     tb_Data;
    } ;

extern struct TrackBase *TrackBase ;

extern void AddProcess(void);
extern void RemoveProcess(void);
extern void TrackItem(void *item,void (*function)(),long param) ;
extern void FreeTrackedItem(void *item);
extern void FreeTrackList(void);
extern void SetTrap(void (*func)());
extern void OnSignal(int signum,void (*func)());
extern struct TrapInfo *GetTrap(void);
extern char *TrapMsg(int code);
extern long Printf(char *fmt,...);
extern long VPrintf(char *fmt,void *args,...);
extern long FPrintf(BPTR fh, char *fmt, ...) ;
extern long VFPrintf(BPTR fh, char *fmt,void *args) ;
extern long __stdargs SPrintf(char *dest, char *fmt, ...) ;
extern long __stdargs VSPrintf(char *dest, char *fmt, void *vec) ;
extern void *MemAlloc(long size, long type) ;
extern void MemFree(char *block) ;
extern struct MsgPort *CreatePort(char *name, long pri) ;
extern void DeletePort(struct MsgPort *port) ;
extern struct IORequest *CreateExtIO(struct MsgPort *ioreply, long size) ;
extern void DeleteExtIO(struct IORequest *ioreq) ;
extern void DeletePacket(struct StandardPacket *pk,long myreply) ;
extern struct StandardPacket *CreatePacket(struct MsgPort *reply) ;
extern long DoPacket(struct StandardPacket *pk, struct MsgPort *dest) ;
extern struct StandardPacket *SendPacket(struct StandardPacket *pk, struct MsgPort *dest) ;
extern long WaitPacket(struct StandardPacket *pk) ;
extern struct StandardPacket *CheckPacket(struct StandardPacket *pk) ;

/*
 * Auto-tracking functions.
 */

extern struct Window *TOpenWindow( struct NewWindow *nw ) ;
extern struct Screen *TOpenScreen( struct NewScreen *screen ) ;
extern char *TMemAlloc(long size, long type) ;
extern struct MsgPort *TCreatePort(char *name, long pri) ;
extern struct IORequest *TCreateExtIO(struct MsgPort *ioreply, long size) ;
extern long TOpenDevice(char *devname,long unit,struct IORequest *ioRequest,long flags) ;
extern char TSetDMRequest(struct Window *win,struct Requester *req) ;
extern char TSetMenuStrip(struct Window *win,struct Menu *mn) ;
extern struct Library *TOpenLibrary(char *lib,int rev) ;
extern BPTR TOpen(char *name, int mode) ;
extern BPTR TLock(char *name, int mode) ;
extern struct StandardPacket *TCreatePacket(struct MsgPort *reply) ;

/*
 * Misc
 */
extern char *Reads(BPTR fh,char *buf, int len) ;
extern BPTR MakeBStr(char *str) ;
extern void NewList(struct List *list) ;
extern void SetJmp(jmp_buf list) ;
extern void LongJmp(jmp_buf list) ;

/*
 * Although the Range checking function is a single function, there are
 * several points you can jump into it, depending on what you wish to check.
 */

/*
 * This accepts a lowbound and a highbound. It makes sure the variable is
 * within the range of low->high.
 */
extern void ChkBound(long var,long min,long max) ;
/*
 * This accepts a lowbound and a size. It makes sure the variable is
 * within the range of low->low+size.
 */
extern void ChkRange(long var,long min,long size) ;
/*
 * This accepts a maximum. It makes sure the variable is
 * within the range of 0->maximum. Note that since CHK is a 16bit
 * instruction, the high word is checked before the low word.
 */
extern void AbsChk(long var,long max) ;
/*
 * This accepts a maximum. It makes sure the variable is
 * within the range of 0->maximum. This works for SHORTS, where the upper
 * 16 bits are not checked.
 */
extern void AbsChkWord(short var,long max) ;
extern void ExceptInit(void *func) ;
extern long ExceptEnter(char *name) ;
extern void ExceptLeave(void) ;
extern void ExceptCall(long code) ;
extern void ExceptRaise(long code,char *name) ;
extern long ExceptCode(void) ;
extern char *Strchr(char *str, int val) ;
extern char *Strcat(char *str, char *data) ;
extern long Atol(char *str) ;
#define ASSERT(x) if (!(x)) RAISEEXCEPTION(EXT_ASSERT_FAIL,0)
