#include	"libdata.h"
#include	"ppcexample.library_VERSION.h"

#define	DEBUG_INIT(x)		x;
#define	DEBUG_OPEN(x)		x;
#define	DEBUG_CLOSE(x)		x;
#define	DEBUG_EXPUNGE(x)	x;
#define	DEBUG_NULL(x)		x;

void	LibEnd(void);

void	(*LibFuncTable[])(void);
struct Library*	LIB_Init(struct LibBase		*MyLibBase,
                         BPTR			SegList,
                         struct ExecBase	*SBase);
extern	ULONG	Dummy;


struct LibInitStruct
{
	ULONG	LibSize;
	void	*FuncTable;
	void	*DataTable;
	void	(*InitFunc)(void);
};

struct LibInitStruct LibInitStruct=
{
	sizeof(struct LibBase),
	LibFuncTable,
	NULL,
	(void (*)(void)) &LIB_Init
};


struct Resident LibResident=
{
	RTC_MATCHWORD,
	&LibResident,
	&LibResident + 1,
	RTF_PPC | RTF_AUTOINIT,
	VERSION,
	NT_LIBRARY,
	0,
	"ppcexample.library",
	VSTRING,
	&LibInitStruct
};

/*
 * To tell the loader that this is a new emulppc elf and not
 * one for the ppc.library.
 * ** IMPORTANT **
 */
ULONG	__amigappc__=1;

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

/* The lib execute init protection which simply returns
 */

ULONG	NoExecute(void)
{
  return(0);
}

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

/*
 * Resident is a RTF_PPC one...that means it`s called
 * natively with normal PPC SysV4 ABI argument order.
 */
struct Library* LIB_Init(struct LibBase		*MyLibBase,
                         BPTR			SegList,
                         struct ExecBase	*SBase)
{
  DEBUG_INIT(dprintf("LibInit: LibBase 0x%lx SegList 0x%lx SBase 0x%lx\n"));

  MyLibBase->SegList	=	SegList;
  MyLibBase->SBase	=	SBase;
  return(&MyLibBase->Lib);
}



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

ULONG	LibExpunge(struct LibBase *MyLibBase)
{
BPTR	MySegment;

  DEBUG_EXPUNGE(dprintf("LIB_Expunge: LibBase 0x%lx <%s> OpenCount %ld\n",
                        MyLibBase,
                        MyLibBase->Lib.lib_Node.ln_Name,
                        MyLibBase->Lib.lib_OpenCnt));

  MySegment	=	MyLibBase->SegList;

  if (MyLibBase->Lib.lib_OpenCnt)
  {
    DEBUG_EXPUNGE(dprintf("LIB_Expunge: set LIBF_DELEXP\n"));
    MyLibBase->Lib.lib_Flags |= LIBF_DELEXP;
    return(NULL);
  }

  /* We don`t need a forbid() because Expunge and Close
   * are called with a pending forbid.
   * But let`s do it for savety if somebody does it by hand.
   */
  Forbid();
  DEBUG_EXPUNGE(dprintf("LIB_Expunge: remove the library\n"));
  Remove(&MyLibBase->Lib);
  Permit();

  DEBUG_EXPUNGE(dprintf("LIB_Expunge: free the library\n"));
  FreeMem((APTR)((ULONG)(MyLibBase) - (ULONG)(MyLibBase->Lib.lib_NegSize)),
          MyLibBase->Lib.lib_NegSize + MyLibBase->Lib.lib_PosSize);

  DEBUG_EXPUNGE(dprintf("LIB_Expunge: return Segment 0x%lx to ramlib\n",
                        MySegment));
  return((ULONG) MySegment);
}

ULONG	LIB_Expunge(void)
{
struct LibBase	*MyLibBase=(struct LibBase*) REG_A6;

  DEBUG_EXPUNGE(dprintf("LIB_Expunge:\n"));
  return(LibExpunge(MyLibBase));
}

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

struct Library*	LIB_Open(void)
{
struct LibBase	*MyLibBase=(struct LibBase*) REG_A6;

  DEBUG_OPEN(dprintf("LIB_Open: 0x%lx <%s> OpenCount %ld\n",
                     MyLibBase,
                     MyLibBase->Lib.lib_Node.ln_Name,
                     MyLibBase->Lib.lib_OpenCnt));


  MyLibBase->Lib.lib_Flags	&=	~LIBF_DELEXP;
  MyLibBase->Lib.lib_OpenCnt++;
  return(&MyLibBase->Lib);
}

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

ULONG	LIB_Close(void)
{
struct LibBase	*MyLibBase=(struct LibBase*) REG_A6;

  DEBUG_CLOSE(dprintf("LIB_Close: 0x%lx <%s> OpenCount %ld\n",
                      MyLibBase,
                      MyLibBase->Lib.lib_Node.ln_Name,
                      MyLibBase->Lib.lib_OpenCnt));

  if ((--MyLibBase->Lib.lib_OpenCnt) > 0)
  {
    DEBUG_CLOSE(dprintf("LIB_Close: done\n"));
  }
  else
  {
    if (MyLibBase->Lib.lib_Flags & LIBF_DELEXP)
    {
      DEBUG_CLOSE(dprintf("LIB_Close: LIBF_DELEXP set\n"));
      return(LibExpunge(MyLibBase));
    }
  }
  return(0);
}

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

ULONG	LIB_Reserved(void)
{
  DEBUG_NULL(dprintf("LIB_Reserved:\n"));

  return(0);
}

