/*
***************************************************************************
*
* Datei:
*	  RSysCheckOffsets.c
*
* Inhalt:
*
*      --- Globale Routinen ---
*
*    void PrintDevOffsets ( LIBRARY *lib );
*    void PrintLibOffsets ( LIBRARY *lib );
*    void SysCheckOffs ( void );
*
*      --- Lokale  Routinen ---
*
*    static void KillMemory ( int kill );
*    static void makeblank ( void );
*    static void makeentry ( ULONG adr , FUNCTION *func );
*    static void makehead ( char *title );
*    static void makeinfo ( struct Library *library , struct 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"

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

struct Remember *FKey = NULL;
struct List FuncList;

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)
{
	struct Node *blanknode = ALLOCF(sizeof(*blanknode));

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

	KillMemory(KILL);

   return;
}

static void
makehead(char *title)
{
	struct 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)
{
	struct 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)
{
	struct 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(struct Library *library, struct List *list)
{
	struct 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, FUNCTION *func)
{
	struct 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)
{
	struct 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(LIBRARY *lib)
{
   FUNCTION *func;
	struct func *funcptr;
   struct Node *fnode;
   struct 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 = (FUNCTION *)fnode;
         funcptr = (struct 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(LIBRARY *lib)
{
   FUNCTION *func;
	struct func *funcptr;
   struct Node *fnode;
   struct Library *library;
	struct IORequest ioreq;
   int unit = 0;
	int	j = 0, err;

	makehead(lib->l_name);

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

   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 = (FUNCTION *)fnode;
         funcptr = (struct 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)
{
	register int i;
	struct Node *node;
	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 = (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;
}

