/******************************************************************************
 *                        FREXX PROGRAMMING LANGUAGE                          *
 ******************************************************************************
 
 libinit.c
 
 Library initialization routines
 
 *****************************************************************************/

/************************************************************************
 *                                                                      *
 * fpl.library - A shared library interpreting script langauge.         *
 * Copyright (C) 1992-1994 FrexxWare                                    *
 * Author: Daniel Stenberg                                              *
 *                                                                      *
 * This program is free software; you may redistribute for non          *
 * commercial purposes only. Commercial programs must have a written    *
 * permission from the author to use FPL. FPL is *NOT* public domain!   *
 * Any provided source code is only for reference and for assurance     *
 * that users should be able to compile FPL on any operating system     *
 * he/she wants to use it in!                                           *
 *                                                                      *
 * You may not change, resource, patch files or in any way reverse      *
 * engineer anything in the FPL package.                                *
 *                                                                      *
 * This program is distributed in the hope that it will be useful,      *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
 *                                                                      *
 * Daniel Stenberg                                                      *
 * Ankdammsgatan 36, 4tr                                                *
 * S-171 43 Solna                                                       *
 * Sweden                                                               *
 *                                                                      *
 * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
 *                                                                      *
 ************************************************************************/

#define  _USEOLDEXEC_ 1
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <exec/resident.h>
#include <exec/libraries.h>
#include <exec/execbase.h>
#include <libraries/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>

#include "liballoc.h"

long _WBenchMsg;

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

int  __saveds __asm __UserLibInit   (register __a6 struct MyLibrary *libbase);
void __saveds __asm __UserLibCleanup(register __a6 struct MyLibrary *libbase);

int  __saveds __asm __UserDevInit   (register __d0 long unit,
                                     register __a0 struct IORequest *ior,
                                     register __a6 struct MyLibrary *libbase);
void __saveds __asm __UserDevCleanup(register __a0 struct IORequest *ior,
                                     register __a6 struct MyLibrary *libbase);

int  __saveds __asm __libfpinit     (register __a6 struct MyLibrary *libbase);
void __saveds __asm __libfpterm     (register __a6 struct MyLibrary *libbase);

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

/* library initialization table, used for AUTOINIT libraries                */
struct InitTable {
        ULONG        *it_DataSize;       /* library data space size         */
        myPFL        *it_FuncTable;      /* table of entry points           */
        APTR         it_DataInit;        /* table of data initializers      */
        myPFL        it_InitFunc;        /* initialization function to run  */
};

/* symbols generated by blink */
extern char __far _LibID[];             /* ID string                        */
extern char __far _LibName[];           /* Name string                      */
extern char __far RESLEN;               /* size of init data                */
extern long __far NEWDATAL;             /* size of global data              */
extern long __far NUMJMPS;              /* number of jmp vectors to copy    */
extern myPFL _LibFuncTab[];             /* my function table                */
extern long __far _LibVersion;          /* Version of library               */
extern long __far _LibRevision;         /* Revision of library              */
#define MYVERSION ((long)&_LibVersion)
#define MYREVISION ((long)&_LibRevision)
#define DATAWORDS ((long)&NEWDATAL)     /* magic to get right tpye of reloc */ 
#define SIZEJMPTAB ((long)libbase->ml_origbase->ml_numjmps)
                                        /* size in bytes of jmp table       */

/* From libent.o, needed to determine where data is loaded by loadseg       */
extern long far _Libmergeddata; 

#define MYLIBRARYSIZE ((sizeof(struct MyLibrary) +3) & ~3)

struct InitTable __far _LibInitTab =  {
        (long *)(&RESLEN+MYLIBRARYSIZE),
        _LibFuncTab,
        NULL,                        /* will initialize my own data */
        _LibInit,
};

__asm ULONG _LibInit( register __a0 APTR seglist,
                      register __d0 struct MyLibrary *libbase )
{
    long *reloc;
    long *sdata;
    char *ddata;
    long nrelocs;

      
    libbase->ml_SegList = (ULONG) seglist;

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

     /* Start of copy of global data after structure */
    ddata = (char *)libbase + MYLIBRARYSIZE; 

    sdata = (long *)&_Libmergeddata; /* where loadseg loaded the data */
    memcpy(ddata, (void *)sdata, DATAWORDS*4);

    /* perform relocs if we want one global section for all programs */
    /* that have this lib open. If we want a global section for each */
    /* open, copy the relocs, and do them on each open call.         */
    sdata = sdata + DATAWORDS;
    nrelocs = *sdata;
    sdata++;
    while (nrelocs > 0)
    {
       reloc = (long *)((long)ddata + *sdata++);
       *reloc += (long)ddata;
       nrelocs--;
    }
    
    if (__UserLibInit(libbase) != 0)
       return NULL; /* abort if user init failed */

    return ( (ULONG) libbase );
}

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

    libbase->ml_DosBase = OpenLibrary("dos.library", 33); /* require 33 */
    if(! libbase->ml_DosBase )
      return NULL; /* we failed! */

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

    /* clear delayed expunges (standard procedure) */
    libbase->ml_Lib.lib_Flags &= ~LIBF_DELEXP;

    return ( (LONG) libbase );
}

ULONG __asm _LibClose( register __a6 struct MyLibrary *libbase )
{
    ULONG retval = 0;
    
    if (( --libbase->ml_Lib.lib_OpenCnt == 0 ) &&
                        ( libbase->ml_Lib.lib_Flags & LIBF_DELEXP ))
    {
        /* no more people have me open,
         * and I have a delayed expunge pending
         */
         retval = _LibExpunge( libbase ); /* return segment list        */
    }

    CloseLibrary( libbase->ml_DosBase ); /* close dos.library */

    return (retval);
}

ULONG __asm _LibExpunge( register __a6 struct MyLibrary *libbase )
{
    ULONG seglist = 0;
    LONG  libsize;

    libbase->ml_Lib.lib_Flags |= LIBF_DELEXP;
    if ( libbase->ml_Lib.lib_OpenCnt == 0 )
    {
        /* really expunge: remove libbase and freemem        */
        __UserLibCleanup(libbase);
        seglist = libbase->ml_SegList;

        Remove( (struct Node *) libbase);

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

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