/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved *
* |. o.| ||          Written by Doug Walker                                 *
* | .  | ||          The Software Distillery                                *
* | o  | ||          235 Trillingham Lane                                   *
* |  . |//           Cary, NC 27513                                         *
* ======             BBS:(919)-471-6436                                     *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#define EXTERN

#include "mydebug.h"
#include "diskwipe.h"

#define MSG_COPYRIGHT 0
#define MSG_DESTROY   1
#define MSG_INSERT    2
#define MSG_USAGE     3
#define MSG_CTRLBK    4
#define MSG_KEEP      5
#define MSG_USE       6

#define MSG_SYS       7
#define MSG_NOMEM     7
#define MSGGETSERR    8
#define MSG_WPROT     8
#define MSG_NODISK    9
#define MSG_BADUNIT  10
#define MSG_INUSE     7
#define MSG_DISKERR  12

char globlen[] =
{
   58, 59, 50, 56, 21, 15, 20, 12, 24, 17, 14, 16,
#ifdef MYDEBUG
   26
#endif
};

char *globmsg[] =
{
   "DISKWIPE 1.0 - Copyright (c) 1987 The Software Distillery\n",
#define DESTROY_SPOT      36
   "\n***** WARNING: All data in drive DF0: will be lost! *****\n",
   "Insert disk and enter new name or press RETURN to ",
   "Usage: diskwipe [MANY] [[DRIVE] <dfn:>] [[NAME] <name>]\n",
   "Press CTRL-\\ to quit\n",
   "keep old name: ",
   "use specified name: ",
   "Fatal error\n",
   "Disk is write protected\n",
   "No disk in drive\n",
   "No such drive\n",
   "Drive in use\n",
#ifdef MYDEBUG
#define DISKERR_SPOT 22
   "Trackdisk error, code    \n"
#endif
   };

void inhibit(arg1)
LONG arg1;
{
   BUG(1, ("inhibit: Entry\n"))
   g.msg->mn_ReplyPort = g.packet->dp_Port = g.replyport;
   g.msg->mn_Node.ln_Name = (char *)g.packet;
   g.msg->mn_Node.ln_Type = NT_MESSAGE;
/*   msg->mn_Length =  0; */

   g.packet->dp_Link = g.msg;
   g.packet->dp_Type = ACTION_INHIBIT;
   g.packet->dp_Arg1 = arg1;
   PutMsg(g.dosport, g.msg);
   WaitPort(g.replyport); 
   (void)GetMsg(g.replyport);
   BUG(1, ("inhibit: Exit, res1 %ld res2 %ld\n", g.packet->dp_Res1, g.packet->dp_Res2))
}

void iopanic()
{
#ifdef MYDEBUG
   short code;
#endif
   register int iomsg;
BUG(1, ("iopanic: Entry, io_Error = %d\n", TDREQ(io_Error)))
   switch(TDREQ(io_Error))
   {
      case TDERR_WriteProt:    iomsg = MSG_WPROT;   break;  /* 28 */
      case TDERR_DiskChanged:  iomsg = MSG_NODISK;  break;  /* 29 */
      case TDERR_BadUnitNum:                                /* 32 */
      case TDERR_BadDriveType: iomsg = MSG_BADUNIT; break;  /* 33 */
      case TDERR_DriveInUse:   iomsg = MSG_INUSE;   break;  /* 34 */
      default:
#ifdef MYDEBUG
         code = (TDREQ(io_Error)) & 255;
BUG(100, ("iopanic: code is %d\n", (unsigned int)code))
         globmsg[MSG_DISKERR][DISKERR_SPOT] = '0' + (short)(code/(short)100);
         code %= (short)100;
BUG(100, ("iopanic: code is %d\n", (unsigned int)code))
         globmsg[MSG_DISKERR][DISKERR_SPOT+1] = '0' + (short)(code/(short)10);
         code %= (short)10;
BUG(100, ("iopanic: code is %d\n", (unsigned int)code))
         globmsg[MSG_DISKERR][DISKERR_SPOT+2] = '0' + code;
         iomsg = MSG_DISKERR;
         break;
#else
     iomsg = MSG_SYS;
#endif
   }
   panic(iomsg);
}

void panic(msgnum)
int msgnum;
{
   BUG(1, ("panic: Entry\n"))
   g.errnum++;

   if(msgnum>=MSGGETSERR) Write(g.outfile, "ERROR: ", 7L);
   PUTTERM(msgnum);

   enditall();
}

void GetName(diskname)
char *diskname;
{
   int i;
   char *tmpchar;
BUG(1, ("GetName: Entry\n"))
#ifdef NOTDOS
   if(!(g.flags & DW_NOTDOS))
   {
#endif
      TDREQ(io_Length) = MYIOSIZE;
      TDIO(CMD_READ);
BUG(100, ("Getname: TDIO done\n"))
      tmpchar = (char *)(TDREQ(io_Data));
      if(tmpchar[3] != 2 || tmpchar[511] != 1) goto DEFNAME;
      memcpy(diskname, tmpchar+433, i=min(30, (int)tmpchar[432]));
      diskname[i] = '\0';
BUG(100, ("GetName: %d chars in name\n", i))
BUG(1, ("GetName: Exit, name is '%s'\n", diskname))
      return;
#ifdef NOTDOS
   }
#endif

DEFNAME:
BUG(10, ("GetName: Root block not initialized, using default\n"))
         strcpy(diskname, "Dos disk");
BUG(1, ("GetName: Exit, name is '%s'\n", diskname))
}

long checksum(block)
long *block;
{
   long sum;
   int i;

   for(i=0, sum = 0L; i<128; i++) sum += block[i];

   BUG(100, ("checksum: returning %ld\n", -sum))
   return(-sum);
}

void makeroot(buffer, diskname)
long *buffer;
char *diskname;
{
   int i;
   memset((char *)buffer, 0, TD_SECTOR);
   buffer[0]   = 2L;   /* Type                        */
   buffer[3]   = 72L;  /* Hashtable size              */
   buffer[79]  = 881L; /* Block to contain the bitmap */
   *(((char *)buffer)+432) = i = strlen(diskname);
   memcpy(((char *)buffer)+433, diskname, i);
   DateStamp(buffer+121);  /* Volume creation date      */
   DateStamp(buffer+105);  /* Volume last modified date */
   buffer[127] = 1L;       /* Secondary type for root   */
   buffer[5] = checksum(buffer);
}

void DosTerm()
{
BUG(1, ("DosTerm: enter\n"))
   if(g.replyport)
   {
BUG(10, ("DosTerm: Disposing of replyport\n"))
      inhibit(0L);
      DisposePort(g.replyport);
      g.replyport = (struct MsgPort *)NULL;
   }
   if(g.msg)    FreeMem((char *)g.msg, sizeof(struct Message));
   if(g.packet) FreeMem((char *)g.packet, sizeof(struct DosPacket));
   g.msg = (struct Message *)(g.packet = (struct DosPacket *)NULL);
BUG(1, ("DosTerm: exit	\n"))
}

void DosInit(device)
int device;
{
   char devname[5];
BUG(1, ("DosInit: Entry\n"))

   strcpy(devname, "df0:");
   devname[2] = '0' + device;

   if( !(g.msg = (struct Message *)AllocMem(sizeof(struct Message), 
                    			  MEMF_PUBLIC|MEMF_CLEAR))      ||
       !(g.packet = (struct DosPacket *)AllocMem(sizeof(struct DosPacket), 
        			   	  MEMF_PUBLIC|MEMF_CLEAR)) ||
       !(g.replyport = NewPort())
     )
      panic(MSG_NOMEM);

   g.dosport = (struct MsgPort *)DeviceProc(devname);
   inhibit(1);
}

void enditall()
{
BUG(1, ("Enditall: Entry\n"))
   TDTerm();
BUG(100, ("Enditall: TDTerm done\n"))
   DosTerm();
BUG(100, ("Enditall: DosTerm done\n"))
   Write(g.outfile, "\n", 1);
   XCEXIT(0);
}

void testbreak()
{
   if (SetSignal(0,0) & (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D))
   {
      Write(g.outfile, "***Break", 8);
      enditall();
   }
}
void main(argc, argv)
int argc;
char *argv[];
{
   char diskname[31];
   char *tmpchar, *usename;
   int nameflag, nexttok, i;

#ifdef MYDEBUG
   int j;
   for(i=0; i<MAXDEBUG; i++) debug[i] = 0;
#endif

   if(argc == 0) XCEXIT(5);

   memset((char *)&g, 0, sizeof(struct MYGLOBAL));

#ifdef MYDEBUG
   if(argc>1 && argv[1][0] == '-' && toupper(argv[1][1]) == 'D')
   {
      if(argv[1][2] == '*') i = -1;
      else (void)stcd_i(argv[1]+2, &i);
      if(i >= MAXDEBUG) i = 0;
      (void)stcd_i(argv[2], &j);
      if(i>= 0)
      {
         debug[i] = j;
         printf("Debugging group %d initialized at level %d\n",i,j);
      }
      else
      {
         for(i=0; i<MAXDEBUG; i++) debug[i] = j;
         printf("All debugging initialized at level %d\n", j);
      }
      argc-=2, argv+=2;
   }
#endif
   BUG(1, ("main: Entry\n"))

   g.outfile = Output();

   usename = diskname;
   nameflag = FALSE;
   for(nexttok=0; argc > 1; argc--, argv++)
   {
      if(argv[1][0] == '?')
      {
         PUTTERM(MSG_COPYRIGHT);
         panic(MSG_USAGE);
      }
      else if(!nexttok && !stricmp(argv[1], "MANY"))
         g.flags |= DW_MANY;
#ifdef NOTDOS
      else if(!nexttok && !stricmp(argv[1], "NOTDOS"))
         g.flags |= DW_NOTDOS;
#endif
      else if(nexttok == 1 || (!nexttok && 
           (toupper(argv[1][0]) == 'D' && toupper(argv[1][1]) == 'F' &&
            (i = argv[1][2] - '0')>=0 && i < 4
          )))
      {
         g.tdunit = i;
         nexttok = 0;
      }
      else if(!nexttok && !stricmp(argv[1], "DRIVE"))
         nexttok = 1;
      else if(!nexttok && !stricmp(argv[1], "NAME"))
         nexttok = 2;
      else if(!nameflag)
      {
         usename = argv[1];
         nameflag = TRUE;
         nexttok = 0;
      }
      else
         panic(MSG_USAGE);
   }

   TDInit();

   DosInit(g.tdunit);

   if(!(TDREQ(io_Data) = (APTR)AllocMem(MYIOSIZE, MEMF_CHIP|MEMF_CLEAR)))
      panic(MSG_NOMEM);

   globmsg[MSG_DESTROY][DESTROY_SPOT] = '0' + g.tdunit;
   PUTTERM(MSG_DESTROY)
   if(g.flags & DW_MANY) PUTTERM(MSG_CTRLBK)

   diskname[30] = '\0';
   do
   {
      TDMotOff();
      PUTTERM(MSG_INSERT)
      PUTTERM(nameflag ? MSG_USE : MSG_KEEP)
      if(!Read(Input(), diskname, 30)) break;
      testbreak();
      if(diskname[0] != '\n' && (tmpchar=strchr(diskname, '\n')) )
      {
         *tmpchar = '\0';
         usename = diskname;
         nameflag = FALSE;
      }
      else if(!nameflag)
         GetName(diskname);

      TDREQ(io_Length)  = MYIOSIZE;

#ifdef NOTDOS
      if(g.flags & DW_NOTDOS)
      {
         strcpy((char *)TDREQ(io_Data), "DOS");
         TDREQ(io_Offset) = 0;
         TDIO(CMD_WRITE);
         TDREQ(io_Offset) = 880*TD_SECTOR;
      }
#endif

      makeroot((long *)TDREQ(io_Data), usename);
      TDIO(CMD_WRITE);
   }
   while(g.flags & DW_MANY);

   enditall();   
}

void TDIO(command)
UWORD command;
{
   BUG(1, ("TDIO: Entry, command %d\n", command))
   TDREQ(io_Command) = command;
   DoIO((struct IORequest *)g.diskreq);
   if(TDREQ(io_Error)) iopanic();
   BUG(1, ("TDIO: Exit\n"))
}

void TDInit()
{
   BUG(1, ("TDInit: Entry\n"))

   if(!(g.diskport = NewPort()) || !(g.diskreq = CreateIOExtTD(g.diskport)))
      panic(MSG_SYS);

   ETDREQ(iotd_Count) = (unsigned long)0xffffffff;
   TDREQ(io_Offset) = 880*TD_SECTOR;

   BUG(10, ("TDInit: Port created, diskreq allocated\n"))

   if(OpenDevice(TD_NAME, g.tdunit, (struct IORequest *)g.diskreq, 0))
      iopanic();

   g.flags |= DW_TDOPEN;

   BUG(1, ("TDInit: Exit\n"))
}

void TDTerm()
{
   BUG(1, ("TDTerm: Entry\n"))

   if(g.flags & DW_TDOPEN)
   {
      if(TDREQ(io_Data))
      {
BUG(100, ("Enditall: freeing io_Data\n"))
         FreeMem((char *)TDREQ(io_Data), MYIOSIZE);
         TDREQ(io_Data) = NULL;
      }
      if(g.errnum<2) TDMotOff();

      CloseDevice((struct IORequest *)g.diskreq);
BUG(10, ("TDTerm: Device closed\n"))

      DeleteIOExtTD(g.diskreq);
BUG(10, ("TDTerm: Diskreq freed\n"))

      g.diskreq = (struct IOExtTD *)NULL;
   }

   if(g.diskport)
   {
      DisposePort(g.diskport);
      g.diskport = (struct MsgPort *)NULL;
BUG(10, ("TDTerm: port deleted\n"))
   }

BUG(1, ("TDTerm: Exit\n"))
}

void TDMotOff()
{
BUG(1, ("TDMotOff: Entry\n"))
   TDREQ(io_Length) = 0;
   if(!TDREQ(io_Error))
   {
BUG(10, ("TDMotOff: Clearing track buffer\n"))
      TDIO((UWORD)ETD_UPDATE);
      TDIO((UWORD)ETD_CLEAR);
   }

   TDIO((UWORD)ETD_MOTOR);
BUG(1, ("TDMotOff: Exit\n"))
}

void MemCleanup(){}
