/*
**	patch.library
**
**	Copyright © 1993-1997 by Stefan Fuchs
**
**      This file is based on:
**
**      $VER: StartUp.c 1.3 (13.9.96)
**
**      Library startup-code and function table definition
**
**      (C) Copyright 1996 Andreas R. Kleinert
**      All Rights Reserved.
**
*/

#ifndef _PATCH_INCLUDES_H
#include "patch_includes.h"
#endif


struct PatchBase * LIBFUNC InitLib( REGA6 struct ExecBase  * GNUC_REGA6,
                                    REGA0 BPTR               GNUC_REGA0,
                                    REGD0 struct PatchBase * GNUC_REGD0);

struct PatchBase * ASMFUNC OpenLib( REGA6 struct PatchBase * GNUC_REGA6);
BPTR  ASMFUNC CloseLib( REGA6 struct PatchBase * GNUC_REGA6);
BPTR  LIBFUNC ExpungeLib( REGA6 struct PatchBase * GNUC_REGA6);
ULONG ASMFUNC ExtFuncLib(void);

ULONG ASMFUNC MemHandlerCode( REGA0 struct Interrupt * GNUC_REGA0, REGA1 struct PatchBase * GNUC_REGA1);


LONG ASMFUNC LibStart(void)
{
	return(-1);
}

extern APTR FuncTab [];
extern struct MyDataInit DataTab;
extern char LibName;

struct InitTable                       /* do not change */
{
 ULONG              LibBaseSize;
 APTR              *FunctionTable;
 struct MyDataInit *DataTable;
 APTR               InitLibTable;
} InitTab =
{
 sizeof(struct PatchBase),
 &FuncTab[0],
 &DataTab,
 InitLib
};

APTR FuncTab [] =                      /* add your own functions here */
{
	OpenLib,
	CloseLib,
	ExpungeLib,
	ExtFuncLib,

	InstallPatch,		/* V1	obsolete */
	WaitRemovePatch,	/* V1	obsolete */
	RemovePatch,		/* V1	obsolete */
	FindPatch,		/* V1	obsolete */

	InstallPatchTagsA,	/* V2 */
	RemovePatchTagsA,	/* V2 */

	FindPatchTagsA,		/* V3 */
	SetPatchA,		/* V3 */
	GetPatchA,		/* V3 */
	PatchFreeVec,		/* V3 */

	RemovePatchProjectA,	/* V4 */
	CreatePatchProjectA,	/* V4 */

	SetPatchProjectA,	/* V5 */
	GetPatchProjectA,	/* V5	(reserved) */
	AddPatchNotifyA,	/* V5 */
	RemPatchNotifyA,	/* V5 */
	PatchAlloc,		/* V5 */

/*	InformWedge,		   V6? */
/*	InternalInstallPatch,	   V6? */
/*	InternalRemovePatch,	   V6? */

	RemovePatchHandler,	/* PRIVATE */

	(APTR) ((LONG)-1)
};


struct PatchBase	*PatchBase	= NULL;
struct ExecBase		*SysBase	= NULL;
struct DosLibrary	*DOSBase	= NULL;
#ifdef __GNUC__
	struct UtilityBase	*UtilityBase	= NULL;
	struct Library *__UtilityBase = NULL;
#else
	struct Library		*UtilityBase	= NULL;
#endif



struct Interrupt MemHandler;

struct PatchBase * LIBFUNC InitLib( REGA6 struct ExecBase  *sysb    GNUC_REGA6,
                                    REGA0 BPTR             seglist  GNUC_REGA0,
                                    REGD0 struct PatchBase *patchb  GNUC_REGD0)
{
	ULONG negsize, possize, fullsize;
	UBYTE *negptr;

	PatchBase = patchb;
	SysBase = sysb;
	PatchBase->PB_SegList = seglist;

	if(SysBase->LibNode.lib_Version >= 37) /* patch.library V6 requires kick V37+ */
	{
		if( DOSBase = (APTR) OpenLibrary("dos.library", 0L)) 
		{
			if( UtilityBase = (APTR) OpenLibrary("utility.library", 0L))
			{
				PatchBase->PB_SysBase = SysBase;
				PatchBase->PB_UtilityBase = (APTR)UtilityBase;
				PatchBase->PB_DosBase = (APTR)DOSBase;

#ifdef __GNUC__
				__UtilityBase = (APTR)UtilityBase;
#endif

				NewList(&(PatchBase->PB_MasterPatchHeader));
				NewList(&(PatchBase->PB_NotifyListHeader));
				NewList(&(PatchBase->PB_ProjectHeader));
				PatchBase->PB_Semaphore.ss_Link.ln_Type = NT_SIGNALSEM;
				InitSemaphore(&(PatchBase->PB_Semaphore));

				Forbid();
				PatchBase->PB_Semaphore.ss_Link.ln_Name = &LibName;
				Enqueue(&(sysb->SemaphoreList), (struct Node *) &(PatchBase->PB_Semaphore));
				Permit();

				PatchBase->PB_OffsetCodeStart = offsetof( struct PatchCode, PC_PatchCodeStart);

				PatchBase->PB_MemoryPool = LibCreatePool( MEMF_CLEAR| MEMF_PUBLIC, 0x800, 0x200);

				if(SysBase->LibNode.lib_Version >= 39)
				{
					MemHandler.is_Node.ln_Pri = 50;
					MemHandler.is_Node.ln_Name = &LibName;
					MemHandler.is_Data = PatchBase;
					MemHandler.is_Code = (void (*) ())MemHandlerCode;
					AddMemHandler(&MemHandler);
				}
				SetupAsmEnv(PatchBase);
/* Set some default values */
				PatchBase->PB_StackExtensions = 5;
				PatchBase->PB_Flags |= PBF_NoStackAllocmem;

				return(PatchBase);
			}
			CloseLibrary((APTR)DOSBase);
		}
	}

	negptr = (UBYTE *) PatchBase;

	negsize  = PatchBase->PB_LibNode.lib_NegSize;
	possize  = PatchBase->PB_LibNode.lib_PosSize;
	fullsize = negsize + possize;
	negptr  -= negsize;

	FreeMem(negptr, fullsize);
	return( NULL);
}

struct PatchBase * ASMFUNC OpenLib( REGA6 struct PatchBase *patchb GNUC_REGA6)
{
	patchb->PB_LibNode.lib_OpenCnt++;
	patchb->PB_LibNode.lib_Flags &= ~LIBF_DELEXP;
	return(patchb);
}

BPTR ASMFUNC CloseLib( REGA6 struct PatchBase *patchb GNUC_REGA6)
{
	patchb->PB_LibNode.lib_OpenCnt--;

	if(!patchb->PB_LibNode.lib_OpenCnt)
	{
		if(patchb->PB_LibNode.lib_Flags & LIBF_DELEXP)
		{
			return( ExpungeLib(patchb) );
		}
	}
	return(NULL);
}



BPTR LIBFUNC ExpungeLib( REGA6 struct PatchBase *PatchBase GNUC_REGA6)
{
	BPTR seglist;

	if(PatchBase->PB_LibNode.lib_OpenCnt == NULL)
	{
		ULONG negsize, possize, fullsize;
		UBYTE *negptr = (UBYTE *) PatchBase;

		RemovePatchHandler();

		if(PatchBase->PB_MasterPatchHeader.lh_Head->ln_Succ)
		{
			PatchBase->PB_LibNode.lib_Flags |= LIBF_DELEXP;
			return(NULL);
		}


		if( PatchBase->PB_PatchFunctionCounter)
		{
			PatchBase->PB_LibNode.lib_Flags |= LIBF_DELEXP;
			return(NULL);
		}

		if(SysBase->LibNode.lib_Version >= 39)
		{
			RemMemHandler(&MemHandler);
		}

		RemSemaphore(&(PatchBase->PB_Semaphore));
		if (PatchBase->PB_MemoryPool)
		{
			LibDeletePool(PatchBase->PB_MemoryPool);
		}

		seglist = PatchBase->PB_SegList;

		Remove((struct Node *)PatchBase);

		if(UtilityBase) CloseLibrary((APTR)UtilityBase);
		if(DOSBase) CloseLibrary((APTR)DOSBase);

		negsize  = PatchBase->PB_LibNode.lib_NegSize;
		possize  = PatchBase->PB_LibNode.lib_PosSize;
		fullsize = negsize + possize;
		negptr  -= negsize;

		FreeMem(negptr, fullsize);

		return(seglist);
	}

	PatchBase->PB_LibNode.lib_Flags |= LIBF_DELEXP;
	return(NULL);
}

ULONG ASMFUNC ExtFuncLib(void)
{
 return(NULL);
}

ULONG LIBFUNC MemHandlerCode( REGA0 struct Interrupt *memhandler GNUC_REGA0, REGA1 struct PatchBase *PatchBase GNUC_REGA1)
{
	RemovePatchHandler();
	return(MEM_ALL_DONE);
}


#if defined(__SASC)

/* for SAS/C's sc.lib only */

ULONG XCEXIT       = NULL;	/* these symbols may be referenced by    */
ULONG _XCEXIT      = NULL;	/* some functions of sc.lib, but should  */
ULONG ONBREAK      = NULL;	/* never be used inside a shared library */
ULONG _ONBREAK     = NULL;
ULONG base         = NULL;
ULONG _base        = NULL;
ULONG ProgramName  = NULL;
ULONG _ProgramName = NULL;
ULONG StackPtr     = NULL;
ULONG _StackPtr    = NULL;
ULONG oserr        = NULL;
ULONG _oserr       = NULL;
ULONG OSERR        = NULL;
ULONG _OSERR       = NULL;

void __regargs __chkabort(void) { }  /* a shared library cannot be    */
void __regargs _CXBRK(void)     { }  /* CTRL-C aborted when doing I/O */

#endif