/*============================================================================*/

/* Fast A-Max.c version 2.5,  written by John O'Leary,  93.3.29 */
/* Upgrade (and rename) of FastMax version 3,  written  90.5.28 */

/* Must be compiled so that parameters are passed on the stack */
/* and function return values are passed back in D0 */
/* and size of  char == byte,  short == word,  long == longword */

/*============================================================================*/

#include <stdio.h>
#include <stdlib.h>

FILE  * F;
char  * InFile1 = "A-Max Startup";
char  * InFile2 = "A-MaxStartup";
char  * InFile;
char  * BackupFile = "Original A-Max Startup";
char  * OutFile = "A-Max Fast Startup";
char  * ROMsFile = "Mac ROMs";
unsigned char  * Buffer, far ROMs [1 << 17];
extern far ReadFile;
unsigned long  (* ReadROM) (unsigned char *, long);
  /* ReadROM is a pointer to a function returning an unsigned long value */
unsigned long  ROM_ID, ROMSize, FileSize, Start, Finish, I;

void  main (int, char * []);
void  CleanUp (unsigned short int, char *, char *, char *);

/*============================================================================*/

void main (argc, argv)

int  argc;
char  * argv [];

   {
   if (argc > 1 & argv [1] [0] == '?' | argc > 3)
      CleanUp (0, "A-Max program patch\nUSAGE: ", argv [0],
       " [Original_filename [Backup_filename]]\n");
   if (argc > 1)  InFile = argv [1];  else  InFile = InFile1;
   if (argc > 2)  BackupFile = argv [2];

/*------------------------------------------------------------------------------
	Read original program file
------------------------------------------------------------------------------*/

   if ((F = fopen (InFile, "r")) == 0)
      if (argc > 1)
         goto NO_INPUT;
      else
         {
         InFile = InFile2;
         if ((F = fopen (InFile, "r")) == 0)
NO_INPUT:
            CleanUp (0, "Couldn't open file '", InFile, "' for input\n");
         }
   fseek (F, 0L, 2);
   if ((FileSize = ftell (F)) <= 0)
      CleanUp (1, "Input file '", InFile, "' is empty.\n");
   if ((Buffer = malloc (FileSize)) == NULL)
      CleanUp (1, "Unable to allocate memory for buffer.\n", "", "");
   printf ("Reading original program file '%s'... ", InFile);
   rewind (F);
   FileSize = fread (Buffer, 1, FileSize, F);
   fclose (F);
   printf ("%ld bytes.\n", FileSize);

/*------------------------------------------------------------------------------
   Search for beginning and end of ReadROM routine
------------------------------------------------------------------------------*/

   printf ("Searching program for ReadROM routine... ");
   for (Start = 0;
    Buffer [Start]   != 0x48 |
    Buffer [Start+1] != 0xE7 |
    Buffer [Start+2] != 0x7F |
    Buffer [Start+3] != 0xFE |
    Buffer [Start+4] != 0x78 |
    Buffer [Start+5] != 0x04 |
    Buffer [Start+6] != 0x20 |
    Buffer [Start+7] != 0x6F;
    Start ++)
      if (Start >= FileSize-100)
         CleanUp (2, "not found.\n", "", "");
   /* Start is index of first byte of ReadROM routine */

   for (Finish = Start+10;
    Buffer [Finish-7] != 0xE3 |
    Buffer [Finish-6] != 0xEB |
    Buffer [Finish-5] != 0xE7 |
    Buffer [Finish-4] != 0xEF |
    Buffer [Finish-3] != 0xF3 |
    Buffer [Finish-2] != 0xFB |
    Buffer [Finish-1] != 0xF7 |
    Buffer [Finish]   != 0xFF;
    Finish ++)
      if (Finish >= FileSize-1)
         CleanUp (2, "not found.\n", "", "");
   /* Finish is index of byte immediately following ReadROM routine */

/*------------------------------------------------------------------------------
   Patch (DiskResource -> dr_Flags) handling in ReadROM routine
   of A-Max version 1 for compatibility with SetPatch
------------------------------------------------------------------------------*/

   for (I = Start;  I < Finish;  I ++)
      if (Buffer [I]   == 0x08 &&
          Buffer [I+1] == 0xE9 &&
          Buffer [I+2] == 0x00 &&
          Buffer [I+3] == 0x07)
         {
         Buffer [I] = 0x08;  Buffer [I+1] = 0x29;  /* replace BSET with BTST */
         }
   printf ("found.\n");

/*------------------------------------------------------------------------------
   Call original ReadROM routine with pointer to ROMs buffer and
   zero longword (needed by ReadROM of A-Max version > 2.0) on the stack
   Amigas with MMUs may not like this!
------------------------------------------------------------------------------*/

   printf ("WARNING:  Interrupts will be disabled for up to 30 seconds... Press RETURN");
   getchar ();
   printf ("Looking for Macintosh ROMs... ");
   ReadROM = (unsigned long (*) ()) & Buffer [Start];
   ROM_ID = ReadROM (ROMs, 0L);

/*------------------------------------------------------------------------------
   The ROM ID is returned in D0
   High word == 0x69 for 64K ROMs, 0x75 for 128K ROMs
   Low word == bit number for drive SEL
------------------------------------------------------------------------------*/

   if (ROM_ID >> 16 == 0x69)
      ROMSize = 1 << 16  /* 64K */;
   else if (ROM_ID >> 16 == 0x75)
      ROMSize = 1 << 17  /* 128K */;
   else
         CleanUp (2, "not found.\n", "", "");
   printf ("%dK ROMs found in drive number %d\n",
    (short) (ROMSize >> 10), (short) ROM_ID - 3);

/*------------------------------------------------------------------------------
   Write ROM ID and contents of ROMs to file
------------------------------------------------------------------------------*/

   if ((F = fopen (ROMsFile, "w")) == 0)
      CleanUp (2, "couldn't open file '", ROMsFile, "' for output\n");
   printf ("Writing contents of ROMs to file '%s'... ", ROMsFile);
   if (fwrite ((unsigned char *) & ROM_ID, 4, 1, F) != 1)
      CleanUp (3, "error.\n", "", "");
   if (fwrite ((unsigned char *) ROMs, 1, ROMSize, F) != ROMSize)
      CleanUp (3, "error.\n", "", "");
   fclose (F);
   printf ("done.\n");

/*------------------------------------------------------------------------------
   Write new program file, with ReadROM replaced by ReadFile routine
------------------------------------------------------------------------------*/

   if ((F = fopen (OutFile, "w")) == 0)
      CleanUp (2, "couldn't open file '", OutFile, "' for output\n");
   printf ("Writing patched program file '%s'... ", OutFile);
   if (fwrite ((unsigned char *) Buffer, 1, Start, F) != Start)
      CleanUp (4, "error.\n", "", "");
   if (fwrite ((unsigned char *) & ReadFile, 1, Finish - Start, F) != Finish - Start)
      CleanUp (4, "error.\n", "", "");
   if (fwrite ((unsigned char *) & Buffer [Finish], 1, FileSize - Finish, F) != FileSize - Finish)
      CleanUp (4, "error.\n", "", "");
   printf ("done.\n");
   fclose (F);
   free (Buffer);

/*------------------------------------------------------------------------------
   Backup original program file
------------------------------------------------------------------------------*/

   printf ("Backing up original '%s' to '%s'... ", InFile, BackupFile);
   remove (BackupFile);
   if (rename (InFile, BackupFile) != 0)
      CleanUp (0, "couldn't rename file.\n", "", "");
   printf ("done.\n");

/*------------------------------------------------------------------------------
   Rename patched program file
------------------------------------------------------------------------------*/

   printf ("Renaming new file '%s' as '%s'... ", OutFile, InFile);
   if (rename (OutFile, InFile) != 0)
      CleanUp (0, "couldn't rename file.\n", "", "");
   printf ("done.\n");
   }

/*============================================================================*/

void CleanUp (Level, Message1, Message2, Message3)

   unsigned short int  Level;
   char  * Message1, * Message2, * Message3;

   {
   printf (Message1);
   printf (Message2);
   printf (Message3);
   switch (Level)
      {
      case (4):
         fclose (F);
         remove (OutFile);
         printf ("%s deleted.\n", OutFile);
         free (Buffer);
         break;
      case (3):
         fclose (F);
         remove (ROMsFile);
         printf ("%s deleted.\n", ROMsFile);
      case (2):
         free (Buffer);
         break;
      case (1):
         fclose (F);
         break;
      }
   exit (20 + Level);
   }
