#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/resident.h>
#include <exec/libraries.h>
#include <libraries/dos.h>
#include <proto/exec.h>
#include <string.h>


/*	This includes the revision information	*/
#include "Plib_rev.h"

/*	Include the custom init and expunge headers

	They MUST be of types:
	BOOL __asm __saveds CustomLibInit( register __a6 struct Library *libbase );
	void __asm __saveds CustomLibExpunge( register __a6 struct Library *libbase );

*/
#include "PointerCust.h"
#define	AND	&&

struct MyLibrary
{
	struct	Library ml_Lib;
	ULONG	ml_SegList;
	ULONG	ml_Flags;
	APTR	ml_ExecBase;	/*	Pointer to ExecBase	*/
	LONG	ml_Data;		/*	Global Data	*/
};


typedef LONG (*PFL)();	/*	pointer to function returning 32-bit int	*/


/*	Library Initialization Table, used for AUTOINIT libraries	*/
struct InitTable
{
	ULONG	*it_DataSize;
	PFL 	*it_FuncTable;
	APTR	it_DataInit;
	PFL 	if_InitFunc;
};

/*	my function table (Generated by Blink)	*/
extern PFL _LibFuncTab[];

extern char __far RESLEN;
extern long __far NEWDATAL;	/*	Generated by Blink	*/

#define DATAWORDS	((long)&NEWDATAL)

/*	We need to define this for the following table	*/
ULONG __asm _LibInit( register __a0 APTR seglist,
	register __d0 struct MyLibrary *libbase );

struct InitTable __far _LibInitTab = 
{
	(long*)(&RESLEN+sizeof( struct MyLibrary ) ),
	_LibFuncTab,
	NULL,
	_LibInit,
};


/*	Need this to determine start of MERGED DATA 	*/
extern long far _Libmergeddata;

/*	Supplied by Blink	*/
extern char __far _LibName[];

/*	Supplied as part of our libent.a	*/
extern char __far _VerString[];

/*
The following #define is to give the EXEC call #pragmas (which were changed
to "libcall Sysbase" to use the absolute location known also as AbsExecBase. 
This is needed during the base level expunge call...
*/
#define SysBase (*((ULONG *)4))


/*
This function is called when the library is first loaded. It does the library
structure initialization and calls the custom library initialization routine
which should setup any custom library stuff and open any other libraries that
will be needed. Note that this routine can not change as the setup must
happen in this order.
*/
ULONG __asm _LibInit( register __a0 APTR seglist,
	register __d0 struct MyLibrary *libbase )
{
long *sdata, *reloc;
char* ddata;
long nrelocs;

	libbase->ml_SegList = (ULONG) seglist;

	/* init. library structure (since I don't do automatic data init.)	*/
	libbase->ml_Lib.lib_Node.ln_Type = NT_LIBRARY;
	libbase->ml_Lib.lib_Node.ln_Name = _LibName;
	libbase->ml_Lib.lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
	libbase->ml_Lib.lib_Version = VERSION;
	libbase->ml_Lib.lib_Revision = REVISION;
	libbase->ml_Lib.lib_IdString = (APTR)_VerString;

	/*	The +4 is a wasted long word, where _Libmergeddata is	*/
	ddata = (char*)&libbase->ml_Data+4;
	sdata = (long*)&_Libmergeddata;
	memcpy(ddata, (char*)sdata, DATAWORDS*4);

	sdata = sdata + DATAWORDS;
	nrelocs = *sdata++;
	while( nrelocs > 0 )
	{
		reloc = (long*)((long)ddata + *sdata++);
		*reloc += (long)ddata;
		nrelocs--;
	}

	if( CustomLibInit(( struct Library *)libbase))
		return((ULONG)libbase);
	else
		return( NULL );
}


/*
This is the entry point that is called when the system wishes that the
library free itself. The library should only free itself if there are not
outstanding open libraries. This routine calls the custom expunge routine
where any custom resources that need to be freed are.

**Note: This routine MUST NEVER BREAK FORBID! that is, it must not do ANYTHING
that could cause a Wait to happen...

Also note that it is best to use as little stack as possible as you are being
called from some other process's context.
*/
ULONG __saveds __asm _LibExpunge( register __a6 struct MyLibrary *libbase )
{
ULONG seglist = 0;
LONG libsize;

	libbase->ml_Lib.lib_Flags |= LIBF_DELEXP;
	if( libbase->ml_Lib.lib_OpenCnt == 0 )
	{
		CustomLibExpunge( (struct Library*)libbase );

		/* really expunge: remove libbase and freemem */

		seglist = libbase->ml_SegList;
		Remove( (struct Node*) libbase );

		libsize = libbase->ml_Lib.lib_NegSize + libbase->ml_Lib.lib_PosSize;
		FreeMem( (char*)libbase - libbase->ml_Lib.lib_NegSize, (LONG)libsize );
	}

	/*	return NULL or real seglist	*/
	return(  (ULONG)seglist );
}



/*
This is the entry point that is called when the library is opened by an
application. It mainly changes the OpenCount and the delayed expunge flags...
*/
LONG __asm _LibOpen( register __a6 struct MyLibrary* libbase )
{
	/* mark us as having another customer */
	libbase->ml_Lib.lib_OpenCnt++;

	/* clear delayed expunges (standard procedure) */
	libbase->ml_Lib.lib_Flags &= ~LIBF_DELEXP;

	return( (LONG) libbase );
}



/*
This is the entry point that is called when the library is closed by an
application. The main use here is to change the open count and to check for
delayed expunge calls...
*/
ULONG __asm _LibClose( register __a6 struct MyLibrary *libbase )
{
ULONG retval = 0;

	if( ( --libbase->ml_Lib.lib_OpenCnt == 0 ) AND
		( libbase->ml_Lib.lib_Flags & LIBF_DELEXP ) )
	{
		/* no more people have me open, and I have a delayed expunge pending */
		retval = _LibExpunge( libbase );	/*	return segment list	*/
	}
	return( retval );
}
