/*
   shutdown_library.c --- simple shutdown library

   This library is compatible with the shutdown library
   written by Olaf Barthel (AmiNet:util/boot/Shutdown2_0.lha).
   It is _NOT_ an update but a twin which is reduced to
   calling the hook functions. You can use the library of your
   preference. An update to the original library will be
   released later (see IDEAS, more ideas are welcome).

   This module is based on code from the original library
   Copyright © 1992 by Olaf `Olsen' Barthel (not for commercial use)

   Written by Bernhard Fastenrath (fasten@shw.com)
*/

#include <exec/types.h>
#include <utility/hooks.h>

#include <proto/exec.h>

#if defined (__GNUC__)
#include <stabs.h>
#endif

#include "shutdown_library.h"

struct ExecBase *SysBase;
struct DosLibrary *DOSBase = NULL;
struct Library *UtilityBase = NULL;
struct Library *ShutdownBase;

MinList ShutdownList;
SignalSemaphore AccessLock;
SignalSemaphore	ShutdownLock;
BYTE Closing = 0;

#if defined (__GNUC__)
const BYTE LibName[] = "shutdown.library";
const BYTE LibIdString[] = "$VER: shutdown.library 2.3 (10-26-95)";
const UWORD LibVersion = 2;
const UWORD LibRevision = 3;
#endif

#if defined (__GNUC__)
#define LIBRT
#define REG(regname)
#define STRUCT_MYLIB struct Library
#else
#define LIBRT __saveds __asm
#define REG(reg-name) register __regname
#define ADDTABL_1(name,arg1);
#define ADDTABL_2(name,arg1,arg2);
#define ADDTABL_3(name,arg1,arg2,arg3);
#define ADDTABL_END();
#define STRUCT_MYLIB struct MyLibrary
#endif

/*** internal functions ***/

static int
CallClientHooks ()
{
  if (ShutdownList.mlh_Head -> mln_Succ)
  {
    ShutdownInfo *Info, *NextInfo;
    Node *Node;
    ULONG Mode;

    Info = (ShutdownInfo *) ShutdownList.mlh_Head;
    while (NextInfo = (ShutdownInfo *) Info -> sdi_Node.mln_Succ)
    {
      Mode = SD_EXIT;
      CallHook (Info -> sdi_Hook, &Mode, NULL);
      Info = NextInfo;
    }
  }
}

static
cleanup ()
{
  if (DOSBase)
    CloseLibrary ((struct Library *) DOSBase);
  DOSBase = NULL;
  if (UtilityBase)
    CloseLibrary ((struct Library *) UtilityBase);
  UtilityBase = NULL;
}

/*** library interface ***/

int LIBRT
__UserLibInit (REG(a6) STRUCT_MYLIB *libbase)
{
  SysBase = *(struct ExecBase **)4;
  ShutdownBase = (struct Library *) libbase;

  if (!(DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", 37)))
    return 1;
  if (!(UtilityBase = OpenLibrary ("utility.library", 37)))
  {
    cleanup ();
    return 1;
  }
  InitSemaphore(&AccessLock);
  InitSemaphore(&ShutdownLock);
  NewList (&ShutdownList);
  return 0; /* success */
}

void LIBRT
__UserLibCleanup (REG(a6) STRUCT_MYLIB *libbase)
{
  cleanup ();
}

ADDTABL_1(LIBRexxDispatch,a0);

LONG LIBRT
LIBRexxDispatch (REG(a0) void *Message)
{
  return 0;
}

ADDTABL_3(LIBAddShutdownInfoTagList,a0,a1,a2);

APTR LIBRT
LIBAddShutdownInfoTagList (REG(a0) Hook *Hook, STRPTR Name, TagItem *TagList)
{
  if (!Closing)
  {
    if (Hook && Name && TagList)
    {
       ShutdownInfo *Info;
       LONG Len = strlen (Name);

       if (Info = (ShutdownInfo *) AllocVec (sizeof (ShutdownInfo) + Len + 1, MEMF_PUBLIC | MEMF_CLEAR))
       {
         ObtainSemaphore (&AccessLock);
         Info -> sdi_Hook = Hook;
         Info -> sdi_Name = (STRPTR)(Info + 1);
         strcpy (Info -> sdi_Name, Name);
         AddTail ((struct List *) &ShutdownList, (struct Node *) Info);
         ReleaseSemaphore (&AccessLock);
         return Info;
       }
     }
   }
   return NULL;
}

ADDTABL_1(LIBRemShutdownInfo,a0);

LONG LIBRT
LIBRemShutdownInfo (REG(a0) ShutdownInfo *Info)
{
  if (!Closing && Info)
  {
     ShutdownInfo *Node, *Next;

     ObtainSemaphore (&AccessLock);
     Node = (ShutdownInfo *) ShutdownList.mlh_Head;
     while (Next = (ShutdownInfo *) Node -> sdi_Node.mln_Succ)
     {
       if (Info == (ShutdownInfo *) Node)
       {
         Remove ((struct Node *) Info);
         FreeVec (Info);
         ReleaseSemaphore (&AccessLock);
         return TRUE;
       }
       Node = Next;
     }
     ReleaseSemaphore (&AccessLock);
  }
  return FALSE;
}

ADDTABL_1(LIBShutdown,d0);

LONG LIBRT
LIBShutdown (REG(d0) ULONG mode)
{
  if (!AttemptSemaphore (&ShutdownLock))
    return FALSE;
  else
  {
    /* mode is ignored by this library but
       not by the original shutdown.libray */

    CallClientHooks ();
    ReleaseSemaphore (&ShutdownLock);
    return TRUE;
  }
  return FALSE;
}

ADDTABL_END();
