/*
   ***************************************************************************
   *
   * Datei:
   *      RSysCheckOffsets.c
   *
   * Inhalt:
   *
   *      --- Globale Routinen ---
   *
   *    void PrintDevOffsets ( RSYS_LIBRARY *lib );
   *    void PrintLibOffsets ( RSYS_LIBRARY *lib );
   *    void SysCheckOffs ( void );
   *
   *      --- Lokale  Routinen ---
   *
   *    static void KillMemory ( int kill );
   *    static void makeblank ( void );
   *    static void makeentry ( ULONG adr , RSYS_FUNCTION *func );
   *    static void makehead ( char *title );
   *    static void makeinfo ( LIBRARY *library , LIST *list );
   *    static void makerominfo ( UBYTE *title , ULONG num );
   *    static void makeromsizeinfo ( UBYTE *title , ULONG num );
   *    static void makesummary ( int count );
   *
   * 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 "RSys.h"
#include "protos.h"


static ULONG kickromstart;

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

  if (kill)
    ErrorHandle ("Library offset memory", MEMORY_ERR, ALLOC_FAIL, KILL);

  return;
}

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

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

  KillMemory (KILL);

  return;
}

static void
makehead (char *title)
{
  NODE *newnode = ALLOCF (sizeof (*newnode));

  if (newnode && (newnode->ln_Name = ALLOCF (BUFSIZE)))
    {
      sprintf (newnode->ln_Name, "---- %s", title);
      AddTail (&FuncList, newnode);

      return;
    }

  KillMemory (KILL);

  return;
}

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

  if (newnode && (newnode->ln_Name = ALLOCF (BUFSIZE)))
    {
      sprintf (newnode->ln_Name, "%s : 0x%08lX", (char *) title, num);
      AddTail (&FuncList, newnode);

      return;
    }

  KillMemory (KILL);

  return;
}

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

  if (newnode && (newnode->ln_Name = ALLOCF (BUFSIZE)))
    {
      sprintf (newnode->ln_Name, "%s : %ld Bytes", (char *) title, num);
      AddTail (&FuncList, newnode);

      return;
    }

  KillMemory (KILL);

  return;
}

static void
makeinfo (LIBRARY * library, LIST * list)
{
  NODE *newnode = ALLOCF (sizeof (*newnode));

  if (newnode && (newnode->ln_Name = ALLOCF (BUFSIZE)))
    {
      sprintf (newnode->ln_Name, "(%ld funcs [%ld FDs] at 0x%08lX)",
	       (library->lib_NegSize / 6), CountNodes (list), library);

      AddTail (&FuncList, newnode);

      return;
    }

  KillMemory (KILL);

  return;
}

static void
makeentry (ULONG adr, RSYS_FUNCTION * func)
{
  NODE *newnode = ALLOCF (sizeof (*newnode));

  if (newnode && (newnode->ln_Name = ALLOCF (BUFSIZE)))
    {
      sprintf (newnode->ln_Name, EntryAttr[LIBRARYOFFS].ea_dataformat,
	   func->f_bias, adr, func->f_public ? "pub" : "prv", func->f_name);

      AddTail (&FuncList, newnode);

      return;
    }

  KillMemory (KILL);

  return;
}

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

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

      AddTail (&FuncList, newnode);

      return;
    }

  KillMemory (KILL);

  return;
}

void
PrintLibOffsets (RSYS_LIBRARY * lib)
{
  RSYS_FUNCTION *func;
  RSYS_func *funcptr;
  NODE *fnode;
  LIBRARY *library;
  int j = 0;

  makehead (lib->l_name);

  library = OpenLibrary ((STRPTR) lib->l_name, 0L);
  if (library)
    {
      makeinfo (library, &(lib->l_functions));

      Forbid ();

      for (fnode = lib->l_functions.lh_Head; fnode->ln_Succ; fnode = fnode->ln_Succ)
	{
	  func = (RSYS_FUNCTION *) fnode;
	  funcptr = (RSYS_func *) ((ULONG) library - (ULONG) func->f_bias);

	  if ((funcptr->adr < kickromstart) || (funcptr->adr > MAGIC_ROM_END))
	    {
	      makeentry (funcptr->adr, func);
	      j++;
	    }
	}

      Permit ();

      CloseLibrary (library);

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

  makeblank ();

  return;
}

void
PrintDevOffsets (RSYS_LIBRARY * lib)
{
  RSYS_FUNCTION *func;
  RSYS_func *funcptr;
  NODE *fnode;
  LIBRARY *library;
  IOREQUEST ioreq;
  int unit = 0;
  int j = 0, err;

  makehead (lib->l_name);

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

  if (!strcmp (lib->l_name, "console.device"))
    unit = -1;

  err = OpenDevice ((STRPTR) lib->l_name, unit, &ioreq, (ULONG) unit);
  if (!err)
    {
      library = &(ioreq.io_Device->dd_Library);

      makeinfo (library, &lib->l_functions);

      Forbid ();

      for (fnode = lib->l_functions.lh_Head; fnode->ln_Succ; fnode = fnode->ln_Succ)
	{
	  func = (RSYS_FUNCTION *) fnode;
	  funcptr = (RSYS_func *) ((ULONG) library - (ULONG) func->f_bias);

	  if ((funcptr->adr < kickromstart) || (funcptr->adr > MAGIC_ROM_END))
	    {
	      makeentry (funcptr->adr, func);
	      j++;
	    }
	}

      Permit ();

      CloseDevice (&ioreq);

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

  makeblank ();

  return;
}


void
SysCheckOffs (void)
{
  int i;
  NODE *node;
  RSYS_LIBRARY *lib;

  HandleHelp (MN_SysCheckOffs);

  PrintHeader (LIBRARYOFFS, NULL);

  EmptyListView ();

  NewList (&FuncList);

  kickromstart = MAGIC_ROM_END - MAGIC_ROM_SIZE;

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

  if (Flags.dummy2)
    for (node = Libraries.lh_Head; node->ln_Succ; node = node->ln_Succ)
      {
	lib = (RSYS_LIBRARY *) node;
	if (lib->l_typ)
	  PrintLibOffsets (lib);
	else
	  PrintDevOffsets (lib);
      }
  else
    {
      makeblank ();
      makehead ((char *) field[NO_FD_FIELD]);
    }

  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, 0);
    }

  KillMemory (NO_KILL);

  PrintStatistics ();

  return;
}
