#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 <proto/dos.h>
#include <string.h>

struct MyLibrary {
        struct       Library ml_Lib;
        ULONG        ml_SegList;
        ULONG        ml_Flags;
        APTR         ml_ExecBase;        /* pointer to exec base */
        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;        /* library data space size         */
        PFL          *it_FuncTable;      /* table of entry points           */
        APTR         it_DataInit;        /* table of data initializers      */
        PFL          it_InitFunc;        /* initialization function to run  */
};

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

extern char __far RESLEN;
extern long __far NEWDATAL; /* Generated by BLINK */
#define DATAWORDS ((long)&NEWDATAL)

ULONG __saveds __asm _LibExpunge( register __a6 struct MyLibrary *libbase );
ULONG __saveds __asm _LibInit( register __a0 APTR seglist,
                                register __d0 struct MyLibrary *libbase );

struct InitTable __far _LibInitTab =  {
        (long *)(&RESLEN+sizeof(struct MyLibrary)),
        _LibFuncTab,
        NULL,                        /* will initialize my own data */
        _LibInit,
};
extern long far _Libmergeddata;    /* Need this to determine start of MERGED DATA */


/* These two are defined by blink */
extern char __far _LibID[];
extern char __far _LibName[];

#define MYREVISION 1

__saveds __asm
ULONG _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 = 1;
        libbase->ml_Lib.lib_Revision = MYREVISION;
        libbase->ml_Lib.lib_IdString = (APTR) _LibID;

	ddata = (char *)&libbase->ml_Data+4;   /* The +4 is a wasted long word,
						  where _Libmergeddata is. */
	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--;
	}

        /* ----- Do library specific public initialization here ----- */

        return ( (ULONG) libbase );
}

LONG __saveds __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 );
}

ULONG __saveds __asm
_LibClose( register __a6 struct MyLibrary *libbase )
{
        ULONG retval = 0;

        if (( --libbase->ml_Lib.lib_OpenCnt == 0 ) &&
                        ( 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);
}

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 )
        {
                /* 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 );
}

