#include <stdlib.h>

#include "DLGRexxBase.h"

#include <exec/execbase.h>
#include <exec/resident.h>

#include <clib/rexxsyslib_protos.h>
#include <clib/exec_protos.h>

#include <pragmas/exec_sysbase_pragmas.h>

#define LIBVERSION 2
#define LIBVER "2"
#define LIBREV "2"

extern   char  *TextRC;

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

   /* This will be the first function of this library. It must return
    * an error to the caller.
    */

LONG ReturnError(VOID) { return(-1); }

/// LibInit()
/****************************************************************************/

   /* LibInit():
    *
    * This is a standard library initialization routine written
    * in `C'. It opens two rom-resident libraries (dos.library
    * and utility.library), the third required library being
    * disk-based. It will be opened in LibOpen().
    */

STATIC struct DLGRexxBase * ASM
LibInit(
   REG(d0) struct DLGRexxBase   *DLGRexxBase,
   REG(a0) BPTR                  Segment,
   REG(a6) struct ExecBase      *ExecBase)
{
   struct   DLGRexxBase   *result = NULL;

      /* We must initialize this for the library open calls to work. */

   SysBase = ExecBase;

   DOSBase     = OpenLibrary("dos.library",37L);
   UtilityBase = OpenLibrary("utility.library",37L);
   DLGBase     = OpenLibrary("dlg.library",6L);

      /* Did the two libraries open? */

   if(DOSBase != NULL && UtilityBase != NULL && DLGBase != NULL)
   {
      result = DLGRexxBase;

         /* Initialize the revision number; all other information
          * will have been initialized by the library loader,
          * using the data in the Resident tag.
          */

      DLGRexxBase->drx_Library.lib_Revision = 1;
      DLGRexxBase->drx_Segment = Segment;
      InitSemaphore(&DLGRexxBase->drx_Semaphore);
   }
   else
   {
      if(DOSBase != NULL)     CloseLibrary(DOSBase);
      if(UtilityBase != NULL) CloseLibrary(UtilityBase);
      if(DLGBase != NULL)     CloseLibrary(DLGBase);

         /* Important: The library base and the jump table
          *            vector must be freed if this auto-init
          *            routine fails.
          */

      FreeMem((BYTE *)DLGRexxBase - DLGRexxBase->drx_Library.lib_NegSize,
              DLGRexxBase->drx_Library.lib_NegSize + DLGRexxBase->drx_Library.lib_PosSize);
   }

   return(result);
}
//-
/// LibOpen()
   /* LibOpen():
    *
    * The library open routine; the first caller to open the
    * library will also open the disk-resident rexxsyslib.library.
    */

STATIC struct DLGRexxBase * ASM
LibOpen(REG(a6) struct DLGRexxBase *DLGRexxBase)
{
   struct   DLGRexxBase   *result   =  NULL;
   UWORD                   openCnt;

   openCnt = DLGRexxBase->drx_Library.lib_OpenCnt;

   DLGRexxBase->drx_Library.lib_Flags &= ~LIBF_DELEXP;
   DLGRexxBase->drx_Library.lib_OpenCnt++;

      /* Start of critical section. */

   ObtainSemaphore(&DLGRexxBase->drx_Semaphore);

   if(openCnt == 0) RexxSysBase = OpenLibrary(RXSNAME,0);

   ReleaseSemaphore(&DLGRexxBase->drx_Semaphore);

      /* End of critical section. */

   if(RexxSysBase != NULL)
      result = DLGRexxBase;
   else
      DLGRexxBase->drx_Library.lib_OpenCnt--;

   return(result);
}
//-
/// LibExpunge
STATIC BPTR ASM
LibExpunge(REG(a6) struct DLGRexxBase *DLGRexxBase)
{
   BPTR result = NULL;

   if(TextRC)  { free(TextRC); TextRC = NULL; }

   if(DLGRexxBase->drx_Library.lib_OpenCnt == 0)
   {
      result = DLGRexxBase->drx_Segment;

      CloseLibrary(DOSBase);
      CloseLibrary(UtilityBase);
      CloseLibrary(DLGBase);

      Remove(DLGRexxBase);

      FreeMem((BYTE *)DLGRexxBase - DLGRexxBase->drx_Library.lib_NegSize,
              DLGRexxBase->drx_Library.lib_NegSize + DLGRexxBase->drx_Library.lib_PosSize);
   }
   else
   {
      DLGRexxBase->drx_Library.lib_Flags |= LIBF_DELEXP;
   }

   return(result);
}
//-
/// LibClose()
STATIC BPTR ASM
LibClose(REG(a6) struct DLGRexxBase *DLGRexxBase)
{
   BPTR result = NULL;

      /* Start of critical section. */

   ObtainSemaphore(&DLGRexxBase->drx_Semaphore);

      /* Close rexxsyslib.library if this the
       * last customer.
       */

   if(DLGRexxBase->drx_Library.lib_OpenCnt == 1)
   {
      if(RexxSysBase != NULL)
      {
         CloseLibrary(RexxSysBase);
         RexxSysBase = NULL;
      }
   }

   ReleaseSemaphore(&DLGRexxBase->drx_Semaphore);

      /* End of critical section. */

   DLGRexxBase->drx_Library.lib_OpenCnt--;

   if(DLGRexxBase->drx_Library.lib_OpenCnt == 0 && (DLGRexxBase->drx_Library.lib_Flags & LIBF_DELEXP))
      result = LibExpunge(DLGRexxBase);

   return(result);
}
//-
/// LibNull()
STATIC LONG
LibNull(VOID)
{
   return(NULL);
}
//-

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

   /* Defined in glue.a */

LONG ASM RexxDispatchGlue(REG(a0) struct RexxMsg *);

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

   /* Library initialization table data; first the four mandatory
    * functions, then the only user function.
    */

APTR LibVectors[] =
{
   LibOpen,
   LibClose,
   LibExpunge,
   LibNull,
   RexxDispatchGlue,
   (APTR)-1
};

   /* This will allocate memory for the library base and make
    * the library ready to use before the init routine is called.
    */

typedef struct Library * (* LIBINIT)();

struct LibInit
{
   ULONG          li_StructureSize;    /* Size of the library structure. */
   APTR *            li_FunctionTable;    /* Library function table. */
   struct LibData *  li_StructureInitTable;  /* Library base initialization table. */
   LIBINIT           li_InitRoutine;         /* Library initialization routine. */
};

STATIC struct LibInit LibraryInit =
{
   sizeof(struct DLGRexxBase),
   LibVectors,
   NULL,
   (LIBINIT)LibInit
};

   /* The library loader searches for the following data
    * structure. It is responsible for initializing and
    * configuring the library base and library function table.
    */

struct Resident LibraryTag =
{
   RTC_MATCHWORD,
   &LibraryTag,
   &LibraryTag + 1,
   RTF_AUTOINIT,
   LIBVERSION,
   NT_LIBRARY,
   0,
   "dlgrexx.library",
   "DLGRexx.library " LIBVER "." LIBREV " "__AMIGADATE__,
   &LibraryInit
};

