/*
***************************************************************************
*
* Datei:
*    RSysCheckOffsets.c
*
* Inhalt:
*    void PrintLibOffsets(struct _liblist *liblist);
*    void PrintDevOffsets(struct _devlist *devlist);
*    void SysCheckOffs(void);
*
* Bemerkungen:
*    Ermittlung der gepatchten Libraries und Devices im ROM.
*
* Erstellungsdatum:
*    07-Jul-93    Rolf Böhme
*
* Änderungen:
*    07-Jul-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSysFunc.h"

static struct func
{
   UWORD jmp;                   /* Assembler-Befehl jmp */
   ULONG adr;                   /* Sprungadresse */
};

struct Remember *FKey = NULL;

#define FKEY            ((struct Remember **)&FKey)
#define ALLOCF(size)    AllocRemember(FKEY,(size),MEMF_CLEAR)
#define FREEF(flag)     FreeRemember(FKEY,(flag))

struct List FuncList;

#define MAGIC_ROM_END   ((ULONG)0x01000000)
#define MAGIC_ROM_SIZE  ((ULONG)(*((ULONG *)0x00FFFFEC)))

static ULONG kickromstart;

#define FUNCOFFS sizeof(struct func)

struct _liblist {
   struct Library    *library;
   UBYTE              libname[19];
   ULONG              firstoff,
                      lastoff;
} libs[] =
{
   { NULL,(UBYTE *)"dos.library",         30L,0L },
   { NULL,(UBYTE *)"exec.library",        30L,0L },
   { NULL,(UBYTE *)"expansion.library",   30L,0L },
   { NULL,(UBYTE *)"gadtools.library",    30L,0L },
   { NULL,(UBYTE *)"graphics.library",    30L,0L },
   { NULL,(UBYTE *)"icon.library",        30L,0L },
   { NULL,(UBYTE *)"intuition.library",   30L,0L },
   { NULL,(UBYTE *)"keymap.library",      30L,0L },
   { NULL,(UBYTE *)"layers.library",      30L,0L },
   { NULL,(UBYTE *)"mathffp.library",     30L,0L },
   { NULL,(UBYTE *)"utility.library",     30L,0L },
   { NULL,(UBYTE *)"workbench.library",   30L,0L }
};

#define LIBCNT   sizeof(libs)/sizeof(struct _liblist)

struct _devlist {
   struct Library    *device;
   UBYTE              devname[19];
   ULONG              firstoff,
                      lastoff,
                      flags;
   long               unit;
} devs[] =
{
   { NULL,(UBYTE *)"console.device",     42L, 0L,(ULONG)(-1), -1L},
   { NULL,(UBYTE *)"input.device",       42L, 0L,(ULONG)0, 0 },
/*   { NULL,(UBYTE *)"ramdrive.device",    42L, 0L,(ULONG)0, 0 }*/
};

#define DEVCNT   sizeof(devs)/sizeof(struct _devlist)


static void
KillMemory(int kill)
{
   FREEF(TRUE);

   if(kill)
      ErrorHandle(MEMORY_ERR, ALLOC_FAIL, KILL);

   return;
}

static void
makeblank(void)
{
   struct Node *blanknode = ALLOCF(sizeof(*blanknode));

   if(blanknode)
   {
      AddTail(&FuncList,blanknode);
      return;
   }

   KillMemory(KILL);
}

static void
makehead(UBYTE *title)
{
   struct Node *newnode = ALLOCF(sizeof(*newnode));

   if(newnode && (newnode->ln_Name = ALLOCF(strlen((char *)title)+1+5)))
   {
      sprintf(newnode->ln_Name,"---- %s",(char *)title);
      AddTail(&FuncList,newnode);

      return;
   }

   KillMemory(KILL);
}

static void
makerominfo(UBYTE *title, ULONG num)
{
   struct Node *newnode = ALLOCF(sizeof(*newnode));

   if(newnode && (newnode->ln_Name = ALLOCF(strlen((char *)title)+3+12)))
   {
      sprintf(newnode->ln_Name,"%s : 0x%08lx",(char *)title, num);
      AddTail(&FuncList,newnode);

      return;
   }

   KillMemory(KILL);
}

static void
makeromsizeinfo(UBYTE *title, ULONG num)
{
   struct Node *newnode = ALLOCF(sizeof(*newnode));

   if(newnode && (newnode->ln_Name = ALLOCF(strlen((char *)title)+3+12)))
   {
      sprintf(newnode->ln_Name,"%s : %lD Bytes",(char *)title, num);
      AddTail(&FuncList,newnode);

      return;
   }

   KillMemory(KILL);
}

static void
makeinfo(struct _liblist *ll)
{
   struct Node *newnode = ALLOCF(sizeof(*newnode));

   if(newnode && (newnode->ln_Name = ALLOCF(50)))
   {
      sprintf(newnode->ln_Name,"(%4ld functions, Address: 0x%08lx)",
             (ll->library->lib_NegSize / 6), ll->library);

      AddTail(&FuncList,newnode);

      return;
   }

   KillMemory(KILL);
}

static void
makeentry(long offs,ULONG adr)
{
   struct Node *newnode = ALLOCF(sizeof(*newnode));

   if(newnode && (newnode->ln_Name = ALLOCF(50)))
   {
      sprintf(newnode->ln_Name,"offs: -%5ld addr: 0x%08lx", offs, adr);

      AddTail(&FuncList,newnode);

      return;
   }

   KillMemory(KILL);
}

static void
makesummary(int count)
{
   struct Node *newnode = ALLOCF(sizeof(*newnode));

   if(newnode && (newnode->ln_Name = ALLOCF(50)))
   {
      sprintf(newnode->ln_Name,"-> %4ld patched offsets found", count);

      AddTail(&FuncList,newnode);

      return;
   }

   KillMemory(KILL);
}

void
PrintLibOffsets(struct _liblist *liblist)
{
   struct func *funcptr;
   LONG  offs;
   int j = 0,l = 0;

   makehead(liblist->libname);

   liblist->library = OpenLibrary(liblist->libname, 0L);
   if (liblist->library)
   {
      makeinfo(liblist);

      Forbid();

      funcptr = (struct func *)liblist->library;
      funcptr -= (liblist->firstoff / FUNCOFFS); /* Die ersten Funktionen ueberspringen */

      liblist->lastoff = (liblist->library->lib_NegSize / 6) * FUNCOFFS;

      for (offs = liblist->firstoff; offs <= liblist->lastoff;
           offs += FUNCOFFS)
      {
         if ((funcptr->adr < kickromstart) || (funcptr->adr > MAGIC_ROM_END))
         {
            makeentry(offs,funcptr->adr);
            j++;
         }

         funcptr--;             /* Naechste Funktion */
      }

      Permit();

      CloseLibrary(liblist->library);

      makesummary(j);
   }
   else
      makehead((UBYTE *)"Can't open library!");

   makeblank();

   return;
}

void
PrintDevOffsets(struct _devlist *devlist)
{
   struct func *funcptr;

   struct IORequest ioreq;
   LONG  offs;
   int   j = 0,
         err;

   makehead(devlist->devname);

   memset(&ioreq,0,sizeof(struct IORequest));

   err = OpenDevice(devlist->devname,devlist->unit,&ioreq,devlist->flags);
   if (!err)
   {
      devlist->device = &(ioreq.io_Device->dd_Library);

      makeinfo((struct _liblist *)devlist);

      Forbid();

      funcptr = (struct func *)devlist->device;
      funcptr -= (devlist->firstoff / FUNCOFFS); /* Die ersten Funktionen ueberspringen */

      devlist->lastoff = (devlist->device->lib_NegSize / 6) * FUNCOFFS;

      for (offs = devlist->firstoff; offs <= devlist->lastoff;
           offs += FUNCOFFS)
      {
         if ((funcptr->adr < kickromstart) || (funcptr->adr > MAGIC_ROM_END))
         {
            makeentry(offs,funcptr->adr);
            j++;
         }

         funcptr--;             /* Naechste Funktion */
      }

      Permit();

      CloseDevice(&ioreq);

      makesummary(j);
   }
   else
      makehead((UBYTE *)"Can't open device!");

   makeblank();

   return;
}


void
SysCheckOffs(void)
{
   register int i;
   struct Node *node;

   PrintHeader(LIBRARYOFFS, NULL);

   EmptyListView();

   NewList(&FuncList);

   kickromstart = MAGIC_ROM_END - MAGIC_ROM_SIZE;

   makehead((UBYTE *)"Kick-ROM Info");
   makerominfo((UBYTE *)"ROM Start ", kickromstart);
   makeromsizeinfo((UBYTE *)"ROM Size  ", MAGIC_ROM_SIZE);
   makeblank();

   for(i = 0; i < LIBCNT; i++)
      PrintLibOffsets(&libs[i]);

   for(i = 0; i < DEVCNT; i++)
      PrintDevOffsets(&devs[i]);

   countentries = CountNodes(&FuncList);

   Entries = AllocScrollEntries(countentries);

   for (i = 0, node = FuncList.lh_Head; i < countentries;
        i++, node = node->ln_Succ)
   {
      strcpy(Entries[i].se_Entry,node->ln_Name);

      AddNodeToList(i, NO_SORT);
   }

   KillMemory(NO_KILL);

   PrintStatistics();

   return;
}

