
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/resident.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <libraries/dos.h>

#include "/playerprefsbase.h"

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/debox_protos.h>

#include <pragmas/exec_old_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/debox_pragmas.h>

#include "/playerprefs_rev.h"

/* #define ROM */

extern char __far _LibID[];
extern char __far _LibName[];


/* A HANDY MACRO FOR MAKEING VERSIONS -- USE SECOND ONE */

#define VSTRA(ver,rev)          #ver"."#rev
#define VERSIONSTR(ver,rev)     VSTRA(ver,rev)

typedef LONG (*PFL)();               /* pointer to function returning 32-bit int        */

/* library initialization table, used for AUTOINIT libraries                */

struct InitTable { 

    ULONG        *it_DataSize;       /* library data space size         */ 
    PFL          *it_FuncTable;      /* table of entry points           */ 
    APTR         it_DataInit;        /* table of data initializers      */ 
    PFL          it_InitFunc;        /* initialization function to run  */
    };


/*****************************************
* EXTERNAL REFERENCES GENERATED BY BLINK *
*****************************************/

extern PFL _LibFuncTab[];                   /* table of library functions generated by blink */

extern char __far RESLEN;
extern long __far NEWDATAL;                 /* Generated by BLINK */

#define DATASIZE  ((long)&RESLEN)
#define DATAWORDS ((long)&NEWDATAL)

extern long __far _Libmergeddata;           /* Need this to determine start * of MERGED DATA */
extern long __far LinkerDB;

ULONG __asm _LibExpunge(register __a6 struct PlayerPrefsBase *libbase);
ULONG __asm _LibInit(register __a0 APTR seglist, register __d0 struct PlayerPrefsBase *libbase);

struct InitTable __far _LibInitTab = { 

    (long *)(sizeof(struct PlayerPrefsBase)), 
    _LibFuncTab, 
    NULL,                                                     /* will initialize my own data */ 
    _LibInit,
    };



/*--------------------------- BASIC LIBRARY FUNCTIONS ---------------------*/

__asm ULONG _LibInit(register __a0 APTR seglist, register __d0 struct PlayerPrefsBase *libbase) {   

    libbase->ppb_SegList = (ULONG) seglist;

    libbase->ppb_Lib.lib_Node.ln_Type = NT_LIBRARY;                     /* init. library structure (since I don't do automatic data init.) */
    libbase->ppb_Lib.lib_Node.ln_Name = _LibName;
    libbase->ppb_Lib.lib_Flags        = LIBF_SUMUSED | LIBF_CHANGED;
    libbase->ppb_Lib.lib_Version      = VERSION;
    libbase->ppb_Lib.lib_Revision     = REVISION;
    libbase->ppb_Lib.lib_IdString     = (APTR)_LibID;

    libbase->ppb_ExecBase = (struct Library *)(*(LONG *)4);

    if (!(libbase->ppb_DeBoxBase = OpenLibrary("debox.library",0L))) return(0);

    if (!(libbase->ppb_GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L))) {

        CloseLibrary(libbase->ppb_DeBoxBase);
        return(0);
        }

    if (!(libbase->ppb_IntuitionBase = OpenLibrary("intuition.library",0L))) {

        CloseLibrary((struct Library *)libbase->ppb_GfxBase);
        CloseLibrary(libbase->ppb_DeBoxBase);
        return(0);
        }

    if (!(libbase->ppb_LowLevelBase = OpenLibrary("lowlevel.library",0L))) {

	CloseLibrary(libbase->ppb_IntuitionBase);
        CloseLibrary((struct Library *)libbase->ppb_GfxBase);
        CloseLibrary(libbase->ppb_DeBoxBase);
        return(0);
        }

    InitSemaphore(&libbase->ppb_LibLock);
    InitSemaphore(&libbase->ppb_CRLock);

    return((ULONG)libbase);
    }




LONG __asm _LibOpen(register __a6 struct PlayerPrefsBase *libbase) { 


    libbase->ppb_Lib.lib_OpenCnt++;                                     /* mark us as having another customer */ 

    libbase->ppb_Lib.lib_Flags &= ~LIBF_DELEXP;                         /* clear delayed expunges (standard procedure) */ 
    
    return((LONG)libbase);
    }



ULONG __asm _LibClose(register __a6 struct PlayerPrefsBase *libbase) { 

ULONG retval = 0; 
    
    if ((--libbase->ppb_Lib.lib_OpenCnt == 0) && (libbase->ppb_Lib.lib_Flags & LIBF_DELEXP))        /* no more people have me open, and I have a delayed expunge pending */
        retval = _LibExpunge(libbase);                                                              /* return segment list */

    return (retval);
    }



ULONG __asm _LibExpunge(register __a6 struct PlayerPrefsBase *libbase) { 

#ifndef NOROM

    libbase->ppb_Lib.lib_Flags &= ~LIBF_DELEXP;
    return(NULL);

#else

ULONG seglist = 0; 
LONG  libsize; 
struct Library *SysBase;

    SysBase     = libbase->ppb_ExecBase;

    libbase->ppb_Lib.lib_Flags |= LIBF_DELEXP; 
    
    if ( libbase->ppb_Lib.lib_OpenCnt == 0 ) 
    {   
        /* really expunge: remove libbase and freemem        */ 
        seglist = libbase->ppb_SegList; 
        if (libbase->ppb_Lib.lib_Node.ln_Succ)
            Remove( (struct Node *) libbase);
        
        /* Close stuff */
        CloseLibrary( libbase->ppb_DeBoxBase );
        CloseLibrary( libbase->ppb_GfxBase );

        libsize = libbase->ppb_Lib.lib_NegSize + libbase->ppb_Lib.lib_PosSize; 
        FreeMem( (char *) libbase - libbase->ppb_Lib.lib_NegSize,
                 (LONG) libsize );
    }

    /* return NULL or real seglist                                */ 
    return ( (ULONG) seglist );

#endif

    }



char * __asm MakeDataSeg( register __a6 struct PlayerPrefsBase *libbase )
{
    long *sdata, *reloc;
    char *ddata;
    long nrelocs;
    struct Library *DeBoxBase, *SysBase;
    
    DeBoxBase = libbase->ppb_DeBoxBase;
    
    SysBase = (struct Library *)(*(LONG *)4);

    if (!(ddata = AllocMem( (long)&RESLEN, MEMF_PUBLIC))) return(NULL);
    MemSet( ddata, 0, (long)&RESLEN );

    sdata = (long *)&LinkerDB; /* &_Libmergeddata; */
    CopyMemQuick((char *)sdata,ddata, DATAWORDS*4);
    
    sdata = sdata + DATAWORDS;
    nrelocs = *sdata++;
    
    while (nrelocs > 0)
    {
        reloc = (long *)((long)ddata + *sdata++);
        *reloc += (long)ddata;
        nrelocs--;
    }

    return( ddata );
}

void __asm FreeDataSeg(     register __a0 UBYTE *dseg,
                            register __a6 struct PlayerPrefsBase *libbase )
{
    FreeMem( dseg, (long)&RESLEN );
}
