/*
   ReFormat.c

   Do a QUICK FORMAT on a drive, and keep the volume label.

   Written by:
      Nickey MacDonald
      i6t4@jupiter.sun.csd.unb.ca
      April 29, 1993

   Written and compiled with SAS C V6.2.

   This code should give you a feel for what the FORMAT command must go
   through, minus the code to do low level formatting of the floppy.
   I thought, at the start, it would be a simple matter of calling three
   or for functions at most...  *HA*  The OS designers sure proved me wrong!
   Oh well..  it was a fun learning experience, and now I have example code
   to work with if I ever have to do this again...
*/


#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>

#include <proto/exec.h>
#include <proto/dos.h>

#include <stdio.h>
#include <string.h>


#define PROGRAM_NAME    "ReFormat"
#define PROGRAM_VERSION "1.0"
#define PROGRAM_DATE    "(1993.04.29)"

/* I can forsee there ever being a device name or volume label larger */
/* that 256 characters...  I sure hope not! */
#define MAX_NAME_LEN 256


/* So the VERSION command can know who we are */
static char *VersionString="$VER: " PROGRAM_NAME " " PROGRAM_VERSION " " PROGRAM_DATE;


/* Disable SAS C's built in CTRL-C handler */
void __regargs __chkabort(void);

void __regargs __chkabort(void)
{
}


int main(int argc, char *argv[])
{
   BPTR floppylock;
   char buf[2];
   char namebuf[MAX_NAME_LEN];
   struct InfoData *idata; /* Must be longword aligned */
   int rv=RETURN_ERROR;
   int justinfo, infogiven;
   int l;
   LONG err;
   int doreformat;
   LONG argarray[4];
   struct RDArgs *argstruct;
   char device[MAX_NAME_LEN];
   int promptmode;
   struct DosList *dlist;

   /* Manual says to initialize with default values */
   argarray[0]=0;
   argarray[1]=0;
   argarray[2]=0;
   argarray[3]=0;

   /* Parse the command line arguments */
   argstruct=ReadArgs("DEVICE=DRIVE/K,NOPROMPT/S,ABOUT/S,VERSION/S", argarray, NULL);

   /* There was/were error(s) in the command line */
   if (argstruct == NULL)
   {
      err=IoErr();
      PrintFault(err, PROGRAM_NAME);
      return(RETURN_ERROR);
   }

   promptmode=argarray[1];

   infogiven=0;

   /* VERSION */
   if (argarray[3] != 0)
   {
      printf(PROGRAM_NAME ": Version " PROGRAM_VERSION " " PROGRAM_DATE "\n");
      infogiven=1;
   }

   /* ABOUT */
   if (argarray[2] != 0)
   {
      printf(PROGRAM_NAME " was written by Nick MacDonald <i6t4@jupiter.sun.csd.unb.ca>\n");
      infogiven=1;
   }

   if ((char *)argarray[0] != NULL)
   {
      strcpy(device, (char *)argarray[0]);
      justinfo=0;
   }
   else
   {
      if (infogiven == 0)
      {
         printf(PROGRAM_NAME ": required argument missing\n");
         rv=RETURN_ERROR;
      }
      else
      {
         rv=RETURN_WARN;
      }
      justinfo=1;
   }

   /* Free up the memory the system used on our behalf */
   FreeArgs(argstruct);

   if (justinfo == 1)  return(rv);

   l=strlen(device);
   if (device[l-1] != ':')
   {
      printf(PROGRAM_NAME ": %s is not a valid parameter.\n", device);
      return(RETURN_ERROR);
   }

   /* I don't think this code is necessary any more...  the check of the */
   /* device list should be more encompassing than this anyway */
   /* Check and make sure we're gonna work on a file system */
/* if (! IsFileSystem(device))
   {
      printf(PROGRAM_NAME ":%s is not a file system.\n", device);
      return(RETURN_ERROR);
   }*/

   /* Make sure its a device and not an ASSIGN */
   device[l-1]='\0';
   dlist=LockDosList(LDF_DEVICES | LDF_READ);
   dlist=FindDosEntry(dlist, device, LDF_DEVICES);
   UnLockDosList(LDF_DEVICES | LDF_READ);
   device[l-1]=':';

   if (dlist == NULL)
   {
      printf(PROGRAM_NAME ":  device (or volume) '%s' is not mounted.\n", device);
      return(RETURN_ERROR);
   }

   /* Should probably use PutStr() rather than printf() to make a smaller */
   /* executable... */
   /* PutStr("test of PutStr()\n"); */

   /* The structure has to be longword aligned, which AllocMem() will */
   /* ensure. */
   if (idata=AllocMem(sizeof(struct InfoData), MEMF_PUBLIC | MEMF_CLEAR))
   {
      /* Need a lock to get volume name and info */
      if ((floppylock=Lock(device, ACCESS_READ)) != NULL)
      {
         doreformat=0;

         /* This is how we get the existing volume name so it can be */
         /* passed to format. */
         if (NameFromLock(floppylock, namebuf, MAX_NAME_LEN))
         {
            /* truncate the colon off the volume name */
            l=strlen(namebuf);
            if (namebuf[l-1] == ':')
            {
               namebuf[l-1]='\0';
            }

            /* We're gonna use the filesystem type for Format() */
            if (Info(floppylock, idata))
            {
               doreformat=1;
            }
            else
            {
               err=IoErr();
               PrintFault(err, PROGRAM_NAME);
            }
         }
         else
         {
            err=IoErr();
            PrintFault(err, PROGRAM_NAME);
         }

         /* Don't need that lock any more...  God help them if they */
         /* change floppies at this stage of the game, well maybe not */
         /* you can test yourself and see what you think... */
         UnLock(floppylock);

         /* We know enuff about the floppy to continue, so lets do so */
         if (doreformat == 1)
         {
            if (promptmode == 0)
            {
               /* Warn the poor user what he just asked for */
               printf(PROGRAM_NAME ":  About to erase all information on\n");
               printf("           volume %s in drive %s!\n", namebuf, device);
               printf("           *** Hit CTRL-C followed by RETURN to abort...\n");
               printf("           *** Hit RETURN to continue...\n");

               /* Wait for input */
               fgets(buf, 2, stdin);
            }

            /* Check for the CTRL-C break signal */
            if (CheckSignal(SIGBREAKF_CTRL_C))
            {
               printf(PROGRAM_NAME ":  User abort.\n");
            }
            else
            {
               /* User didn't break, so away we go... */

               if (Inhibit(device, DOSTRUE))
               {
                  /* now inhibited... */

                  /* This should be the same as a FORMAT QUICK */
                  if (Format(device, namebuf, idata->id_DiskType))
                  {
                     printf("ReFormat:  Volume %s was erased.\n", namebuf);
                     rv=RETURN_OK;
                  }
                  else
                  {
                     err=IoErr();
                     PrintFault(err, "ReFormat");
                     printf("ReFormat:  Volume %s was not erased!\n", namebuf);
                  }

                  /* Unhibit the drive ... */
                  if (Inhibit(device, FALSE))
                  {
                  }
                  else
                  {
                     err=IoErr();
                     PrintFault(err, PROGRAM_NAME);
                  }
               }
               else
               {
                  err=IoErr();
                  PrintFault(err, PROGRAM_NAME);
               }
            }
         }
      }
      else
      {
         err=IoErr();
         PrintFault(err, PROGRAM_NAME);
      }

      FreeMem(idata, sizeof(struct InfoData));
   }
   else
   {
      printf(PROGRAM_NAME ":  Could not AllocMem()!\n");
   }

   return(rv);
}
