/*
   shutdown_library.c --- shutdown library interface.

   (c) Copyright 1995 SHW Wabnitz
   Written by Bernhard Fastenrath (fasten@shw.com)

   This file may be distributed under the terms
   of the GNU General Public License.
*/

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

#include "shutdown_library.h"

struct ExecBase *SysBase = NULL;
struct DosLibrary *DOSBase = NULL;
struct Library *ShutdownBase = NULL;
struct List Clients;
ULONG ClientsListBusy = 0;

#if defined (__GNUC__)
const BYTE LibName[] = "shutdown.library";
const BYTE LibIdString[] = "$VER: shutdown.library 1.0 (8-30-95)";
const UWORD LibVersion = 1;
const UWORD LibRevision = 0;
#endif

#if defined (__GNUC__)
#define LIBRT
#define REG_a6
#define REG_d1
#define STRUCT_MYLIB struct Library
#else
#define LIBRT __saveds __asm
#define REG_a6 register __a6
#define REG_d1 register __d1
#define ADDTABL_1(name,arg1);
#define ADDTABL_END();
#define STRUCT_MYLIB struct MyLibrary
#endif

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

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;
  NewList (&Clients);
  return 0; /* success */
}

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

ADDTABL_1(LIBReboot,d1);

int LIBRT
LIBReboot (REG_d1 int flags)
{
  if (flags)
  {
    Disable ();
    while (1);
  }
  ColdReboot ();
  return 1;
}

ADDTABL_1(LIBUnmount,d1);

int LIBRT
LIBUnmount (REG_d1 char *filesystem)
{
  return unmount (NULL, filesystem);
}

ADDTABL_1(LIBAddShutdownPort,d1);

int LIBRT
LIBAddShutdownPort (REG_d1 MsgPort *prt)
{
  ShutdownClient *sc;

  if (!(sc = (ShutdownClient *) AllocMem (sizeof (ShutdownClient), MEMF_PUBLIC)))
    return 0;

  sc -> port = prt;
  sc -> done = 0;
  Forbid ();
  AddHead (&Clients, (Node *) sc);
  Permit ();
  return 1;
}

ADDTABL_1(LIBRemShutdownPort,d1);

int LIBRT
LIBRemShutdownPort (REG_d1 MsgPort *prt)
{
  MinNode *mln;
  int ret = 0;

  Forbid ();
  for (mln = (MinNode *) Clients.lh_Head; mln -> mln_Succ; mln = mln -> mln_Succ)
    if (((ShutdownClient *) mln) -> port == prt)
    {
      if (ClientsListBusy)
	((ShutdownClient *) mln) -> done = 1;
      else
      {
        Remove ((Node *) mln);
	FreeMem (mln, sizeof (ShutdownClient));
      }
      ret = 1;
      break;
    }
  Permit ();
  return ret;
}

ADDTABL_1(LIBShutdownStatus,d1);

int LIBRT
LIBShutdownStatus (REG_d1 ShutdownMessage *smsg)
{
  ShutdownClient *sc, *next;
  MsgPort *prt;
  Task *me;

  if (IsListEmpty (&Clients))
    return 1;

  me  = FindTask (0);
  prt = smsg -> sm_Msg.mn_ReplyPort;

  Forbid ();
  ClientsListBusy ++;
  Permit ();
  sc = (ShutdownClient *) Clients.lh_Head;  

  while (next = (ShutdownClient *) sc -> node.mln_Succ)
  {
    if (sc -> done)
    {
      Forbid ();
      if (ClientsListBusy == 1)
      {
        Remove ((Node *) sc);
        FreeMem (sc, sizeof (ShutdownClient));
      }
      Permit ();
    }
    else
    {
      if (sc -> port -> mp_SigTask != me)
      {
        PutMsg (sc -> port, (Message *) smsg);
	do
          WaitPort (prt);
        while (!GetMsg (prt));
      }
    }
    sc = next;
  }
  Forbid ();
  ClientsListBusy --;
  Permit ();
  return 1;
}

ADDTABL_END();

