/* Programmheader

	Name:		init.c
	Main:		reko
	Versionstring:	$VER: init.c 1.1 (18.10.1999)
	Author:		SDI
	Distribution:	Freeware
	Description:	all the datatype initialization stuff

 1.0   19.09.99 : first version
 1.1   18.10.99 : fixed the stuff a bit
*/

#include <proto/exec.h>
#include <proto/intuition.h>
#include <dos/dos.h>
#include <exec/resident.h>
#include <exec/initializers.h>
#include <exec/execbase.h>
#include "SDI_compiler.h"

#include "reko.h"

struct LibInitData {
 UBYTE i_Type;     UBYTE o_Type;     UBYTE  d_Type;	UBYTE p_Type;
 UBYTE i_Name;     UBYTE o_Name;     STRPTR d_Name;
 UBYTE i_Flags;    UBYTE o_Flags;    UBYTE  d_Flags;	UBYTE p_Flags;
 UBYTE i_Version;  UBYTE o_Version;  UWORD  d_Version;
 UBYTE i_Revision; UBYTE o_Revision; UWORD  d_Revision;
 UBYTE i_IdString; UBYTE o_IdString; STRPTR d_IdString;
 ULONG endmark;
};

/************************************************************************/

/* First executable routine of this library; must return an error
   to the unsuspecting caller */
LONG ReturnError(void)
{
  return -1;
}

/************************************************************************/

/* The mandatory reserved library function */
ULONG LibReserved(void)
{
  return 0;
}

/************************************************************************/

ASM(struct Library *) LibInit(REG(d0, struct ClassBase *cb), REG(a0, BPTR seglist), REG(a6, struct ExecBase * SysBase))
{
#ifdef _M68060
  if(!(SysBase->AttnFlags & AFF_68060))
    return 0;
#elif defined (_M68040)
  if(!(SysBase->AttnFlags & AFF_68040))
    return 0;
#elif defined (_M68030)
  if(!(SysBase->AttnFlags & AFF_68030))
    return 0;
#elif defined (_M68020)
  if(!(SysBase->AttnFlags & AFF_68020))
    return 0;
#endif
  InitSemaphore(&cb->cb_Lock);

  cb->cb_SegList = seglist;
  cb->cb_SysBase = SysBase;
  if((cb->cb_IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",39)))
  {
    if((cb->cb_GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 39)))
    {
      if((cb->cb_DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 39)))
      {
	if((cb->cb_UtilityBase = (struct UtilityBase *) OpenLibrary ("utility.library", 39)))
	  return (struct Library *) cb;

	CloseLibrary((struct Library *) cb->cb_DOSBase);
      }
      CloseLibrary((struct Library *) cb->cb_GfxBase);
    }
    CloseLibrary((struct Library *) cb->cb_IntuitionBase);
  }

  FreeMem((STRPTR) cb - cb->cb_Lib.lib_NegSize, cb->cb_Lib.lib_NegSize + cb->cb_Lib.lib_PosSize);
  return 0;
}

ASM(struct ClassBase *) LibOpen(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;
  struct ClassBase *ret = cb;

  ObtainSemaphore(&cb->cb_Lock);

  cb->cb_Lib.lib_Flags &= ~LIBF_DELEXP;
  cb->cb_Lib.lib_OpenCnt++;

  if(!cb->cb_Class)
  {
    if((cb->cb_DataTypesBase = OpenLibrary ("datatypes.library", 39)))
    {
      if((cb->cb_SuperClassBase = OpenLibrary ("datatypes/picture.datatype", 39)))
      {
	if((cb->cb_Class = initClass(cb)))
	{
          ReleaseSemaphore(&cb->cb_Lock);
          return ret;
	}
	CloseLibrary(cb->cb_SuperClassBase);
      }
      CloseLibrary(cb->cb_DataTypesBase);
    }
    cb->cb_Lib.lib_OpenCnt--;
    ret = 0;
  }

  ReleaseSemaphore(&cb->cb_Lock);
  return ret;
}

ASM(LONG) LibExpunge(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;

  if(!cb->cb_Lib.lib_OpenCnt)
  {
    if(cb->cb_Class) /* security, should never happen */
    {
      struct IntuitionBase *IntuitionBase = cb->cb_IntuitionBase;
      if(FreeClass(cb->cb_Class))
      {
        cb->cb_Class = 0;
        CloseLibrary(cb->cb_SuperClassBase);
        CloseLibrary(cb->cb_DataTypesBase);
      }
    }
    if(!cb->cb_Class)
    {
      BPTR seg = cb->cb_SegList;

      Remove((struct Node *) cb);
      CloseLibrary((struct Library *) cb->cb_UtilityBase);
      CloseLibrary((struct Library *) cb->cb_DOSBase);
      CloseLibrary((struct Library *) cb->cb_GfxBase);
      CloseLibrary((struct Library *) cb->cb_IntuitionBase);

      FreeMem((STRPTR) cb - cb->cb_Lib.lib_NegSize, cb->cb_Lib.lib_NegSize + cb->cb_Lib.lib_PosSize);

      return seg;
    }
  }
  cb->cb_Lib.lib_Flags |= LIBF_DELEXP;
  return 0;
}

ASM(LONG) LibClose(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;

  ObtainSemaphore(&cb->cb_Lock);

  if(cb->cb_Lib.lib_OpenCnt)
    cb->cb_Lib.lib_OpenCnt--;

  if(!cb->cb_Lib.lib_OpenCnt && cb->cb_Class)
  {
    struct IntuitionBase *IntuitionBase = cb->cb_IntuitionBase;
    if(FreeClass(cb->cb_Class))
    {
      cb->cb_Class = 0;
      CloseLibrary(cb->cb_SuperClassBase);
      CloseLibrary(cb->cb_DataTypesBase);
    }
  }

  ReleaseSemaphore(&cb->cb_Lock);
  /* A bit dangerous, but we cannot release a semaphore after expunging! */
  return (cb->cb_Lib.lib_Flags & LIBF_DELEXP) ? LibExpunge(cb) : 0;
}

/************************************************************************/

ASM(Class *) ObtainEngine(REG(a6, struct ClassBase *cb))
{
  return cb->cb_Class;
}

/************************************************************************/

/* This is the table of functions that make up the library. The first
   four are mandatory, everything following it are user callable
   routines. The table is terminated by the value -1. */

static const APTR LibVectors[] = {
  LibOpen,
  LibClose,
  LibExpunge,
  LibReserved,
  ObtainEngine,
  (APTR)-1
};

static const struct LibInitData LibInitData = {
 0xA0, (UBYTE) OFFSET(Node,    ln_Type),      NT_LIBRARY,		 0,
 0x80, (UBYTE) OFFSET(Node,    ln_Name),      CLASSNAME,
 0xA0, (UBYTE) OFFSET(Library, lib_Flags),    LIBF_SUMUSED|LIBF_CHANGED, 0,
 0x90, (UBYTE) OFFSET(Library, lib_Version),  VERSION,
 0x90, (UBYTE) OFFSET(Library, lib_Revision), REVISION,
 0x80, (UBYTE) OFFSET(Library, lib_IdString), IDSTRING,
 0
};

/* The following data structures and data are responsible for
   setting up the Library base data structure and the library
   function vector. */

static const ULONG LibInitTable[4] = {
  (ULONG)sizeof(struct ClassBase), /* Size of the base data structure */
  (ULONG)LibVectors,             /* Points to the function vector */
  (ULONG)&LibInitData,           /* Library base data structure setup table */
  (ULONG)LibInit                 /* The address of the routine to do the setup */
};

/************************************************************************/

/* The library loader looks for this marker in the memory
   the library code and data will occupy. It is responsible
   setting up the Library base data structure.
*/

static const struct Resident RomTag = {
  RTC_MATCHWORD,                /* Marker value. */
  (struct Resident *)&RomTag,   /* This points back to itself. */
  (struct Resident *)&RomTag+1, /* This points behind this marker. */
  RTF_AUTOINIT,                 /* The Library should be set up according to the given table. */
  VERSION,                      /* The version of this Library. */
  NT_LIBRARY,                   /* This defines this module as a Library. */
  0,                            /* Initialization priority of this Library; unused. */
  CLASSNAME,                    /* Points to the name of the Library. */
  IDSTRING,                     /* The identification string of this Library. */
  (APTR)&LibInitTable           /* This table is for initializing the Library. */
};
