/*
	Library startup-code and function table definition
*/

#define __USE_SYSBASE        // perhaps only recognized by SAS/C

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <exec/execbase.h>
#include <exec/resident.h>
#include <exec/initializers.h>


#ifdef __MAXON__
#include <pragma/exec_lib.h>
#include <linkerfunc.h>
#else
#include <proto/exec.h>    // all other compilers
#endif

#include "compiler.h"
#include "libraries.h"
#include "plugins/pluginbase.h"

#include "clib/plugins_protos.h"


extern ULONG SAVEDS STDARGS L_OpenLibs(void);
extern void  SAVEDS STDARGS L_CloseLibs(void);


struct PLUGINBASE * SAVEDS ASM	InitLib(REG(a6) struct ExecBase * GNUCREG(a6),
		REG(a0) struct SegList * GNUCREG(a0),
		REG(d0) struct PLUGINBASE * GNUCREG(d0));
struct PLUGINBASE * SAVEDS ASM	OpenLib(REG(a6) struct PLUGINBASE * GNUCREG(a6));
APTR SAVEDS ASM					CloseLib(REG(a6) struct PLUGINBASE * GNUCREG(a6));
APTR SAVEDS ASM					ExpungeLib(REG(a6) struct PLUGINBASE * GNUCREG(a6));
ULONG ASM							ExtFuncLib(void);


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


extern APTR FuncTab[];
extern struct MyDataInit DataTab;

struct InitTable InitTab = {
	sizeof(struct PLUGINBASE),
	&FuncTab[0],
	&DataTab,
	InitLib
};

APTR FuncTab[] = {
	OpenLib,
	CloseLib,
	ExpungeLib,
	ExtFuncLib,

	PL_ProcessMessageA,
	PL_GetAttrA,

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

extern struct PLUGINBASE *PLUGINBASE;

struct PLUGINBASE * SAVEDS ASM InitLib(REG(a6) struct ExecBase *sysbase GNUCREG(a6),
		REG(a0) struct SegList *seglist GNUCREG(a0),
		REG(d0) struct PLUGINBASE *clb GNUCREG(d0))
{
	PLUGINBASE = clb;

	PLUGINBASE->clb_SysBase	= sysbase;
	PLUGINBASE->clb_SegList	= seglist;

	if (L_OpenLibs())
		return (PLUGINBASE);

	L_CloseLibs();

	{
		ULONG negsize, possize, fullsize;
		UBYTE *negptr = (UBYTE *)PLUGINBASE;

		negsize	= PLUGINBASE->clb_LibNode.lib_NegSize;
		possize	= PLUGINBASE->clb_LibNode.lib_PosSize;
		fullsize	= negsize + possize;
		negptr	-= negsize;

		FreeMem(negptr, fullsize);

#ifdef __MAXON__
		CleanupModules();
#endif
	}

	return (NULL);
}

struct PLUGINBASE * SAVEDS ASM OpenLib(REG(a6) struct PLUGINBASE *clb GNUCREG(a6))
{
#ifdef __MAXON__
	GetBaseReg();
	InitModules();
#endif

	clb->clb_LibNode.lib_OpenCnt++;

	clb->clb_LibNode.lib_Flags &= ~LIBF_DELEXP;

	return (clb);
}

APTR SAVEDS ASM CloseLib(REG(a6) struct PLUGINBASE *clb GNUCREG(a6))
{
	clb->clb_LibNode.lib_OpenCnt--;

	if (!clb->clb_LibNode.lib_OpenCnt)
		if (clb->clb_LibNode.lib_Flags & LIBF_DELEXP)
			return (ExpungeLib(clb));

	return (NULL);
}

APTR SAVEDS ASM ExpungeLib(REG(a6) struct PLUGINBASE *clb GNUCREG(a6))
{
	struct PLUGINBASE *classbase = clb;
	struct SegList *seglist;

	if (!classbase->clb_LibNode.lib_OpenCnt) {
		ULONG negsize, possize, fullsize;
		UBYTE *negptr = (UBYTE *)classbase;

		seglist = classbase->clb_SegList;

		Remove((struct Node *)classbase);

		L_CloseLibs();

		negsize	= classbase->clb_LibNode.lib_NegSize;
		possize	= classbase->clb_LibNode.lib_PosSize;
		fullsize	= negsize + possize;
		negptr	-= negsize;

		FreeMem(negptr, fullsize);

#ifdef __MAXON__
		CleanupModules();
#endif

		return (seglist);
	}

	classbase->clb_LibNode.lib_Flags |= LIBF_DELEXP;

	return (NULL);
}

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

struct PLUGINBASE *PLUGINBASE = NULL;

/*
	turn off internal CTRL-C handling for standard C functions
*/
#ifdef __SASC

void REGARGS __chkabort(void) { }
void REGARGS _CXBRK(void)     { }

#endif /* __SASC */
