#include "DFC5.h" #define ESC 0x1B #define RETURN 0x0D /* * Mask for EnableGadgets */ #define ALLMASK 0x1FFFF #define COPYMASK 0x03D00 #define AGAINMASK 0x03D00 #define FORMATMASK 0x03700 #define ALLMSGS 0x3F static char Key2Gadget[39] = { DF0S, DF1S, DF2S, DF3S, DF0D, DF1D, DF2D, DF3D, -1, -1, -1, -1, -1, -1, -1, -1, -1, AUTO, BUFFER, -1, DATE, -1, FORMAT, GO, -1, -1, -1, -1, -1, -1, FFS, -1, -1, -1, REPEAT, STOP, TALK, -1, VERIFY }; static char NoBufferMsg[] = "Sorry, I need a buffer."; static char NoDiskMsg[] = "Can't open disk."; static char NoDestMsg[] = "Sorry, I need a destination."; static char NoSourceMsg[] = "Sorry, I need a source."; static char NoDiskPresentMsg[] = "No disk in unit x."; static char WriteProtectedMsg[] = "Disk in unit x is write protected."; static char GfxName[] = "graphics.library"; extern struct MsgPort *MainPort; static struct Window *Window; static char *FormatBuffer, MsgLocked[6], Source = -1, Dest, ActualSource, ActualDest, Verify=1, Buffer, BufferUsed, BufferTrack, Date=1, UseFFS, Fuga, Copying, Formatting, Passes = 1, CurrentPass, CurrentStartTrack, CurrentEndTrack, Track, TracksPerPass = 80; /* * This routine sends an internal message with given parameters and locks it. */ void SendAndLockMsg(int Unit, int Action, int n) { SendMsg(Unit, Action, n); MsgLocked[Unit] = 1; } /* * The same, but the message is simply re-sent (for retrying errors). */ void ReSendAndLockMsg(struct IMsg *Message) { SendAndLockMsg(Message->im_ID, Message->im_Action, Message->im_n); } /* * Check if units in the Mask have locked msgs. */ int NoLockedMsgs(int Mask) { register int i; for(i=0; i<6; i++) if (MsgLocked[i] && (DEST(i) & Mask)) return(FALSE); return(TRUE); } /* * Here we stop any operation. If we weren't copying, and the buffer is on, * we wipe the progress bar and reset the pass counter. */ void Stop(void) { if (Copying) { if (Copying == 'G' && Buffer) if (--CurrentPass<0) CurrentPass = Passes-1; Copying = 0; Track = CurrentEndTrack-1; Beep(2400); } else { CurrentPass = Passes-1; if (Buffer) WipeProgress(Window, 0); } } /* * Here we check if some fatal error was encountered. */ int FatalErrors(struct IMsg *Message) { if (Message->im_RC == NO_DISK) { NoDiskPresentMsg[16] = 48+Message->im_ID; Acknowledge(NoDiskPresentMsg); return(1); } if (Message->im_RC == WRITE_PROTECTED) { WriteProtectedMsg[13] = 48+Message->im_ID; Acknowledge(WriteProtectedMsg); return(1); } return(0); } /* * The big thing! * Apart from the open-all-stuff/close-all-stuff parts, this is simply a * preposterously huge event loop. */ void _main(void) { register int i; register char *b; register struct Gadget *G; struct IMsg *Message; struct IntuiMessage *Msg; int Op, Class, Code; if ((GfxBase = (void *)OpenLibrary(GfxName,36))==NULL) { if ((GfxBase = (void *)OpenLibrary(GfxName,33))==NULL) goto GameOver; ReverseBorderColors(); } if (!SetUpPorts() || (IntuitionBase = (void *)OpenLibrary("intuition.library",33))==NULL || (Window = SetUpWindow())==NULL) goto GameOver; SetUpAudio(); FOREVER { do { Msg = (void *)GetMsg(Window->UserPort); Message = (void *)GetMsg(MainPort); if (Msg) { Code = Msg->Code ; Class = Msg->Class; G = (struct Gadget *)(Msg->IAddress); ReplyMsg((void *)Msg) ; switch(Class) { case CLOSEWINDOW: Fuga = 1; break; case GADGETUP: case GADGETDOWN: case VANILLAKEY: if (Class == VANILLAKEY) { Op = toupper(Code); if (Op>='0' && Op<='V' && Key2Gadget[Op]>=0) G = GAddr(Key2Gadget[Op-48]); else G = NULL; } else Op = G->GadgetID; switch(Op) { case RETURN: Op = Buffer ? 'R' : 'G'; case 'F': case 'R': case 'G': if (Copying || !NoLockedMsgs(ALLMSGS) || (Op == 'F' && !(FormatBuffer = AllocMem(TRACKSIZE, MEMF_PUBLIC)))) break; if (Op == 'G' && Source<0) { Acknowledge(NoSourceMsg); break; } if (((Op == 'G' && INDEST(Source)) || Op == 'R') && !Buffer) { Acknowledge(NoBufferMsg); break; } if ((Op == 'R' || Op == 'F' || (Op == 'G' && !Buffer)) && !Dest) { Acknowledge(NoDestMsg); break; } ActualDest = Dest; switch(Copying = Op) { case 'G': EnableGadgets(Window, COPYMASK); ActualSource = Source; if (Buffer) ActualDest = DEST(4); if (++CurrentPass == Passes) CurrentPass = 0; break; case 'R': EnableGadgets(Window, AGAINMASK); ActualSource = 4; break; case 'F': EnableGadgets(Window, FORMATMASK); ActualSource = 5; break; } if (Formatting = (Copying == 'F')) { CurrentStartTrack = 79; CurrentEndTrack = 0; } else { CurrentStartTrack = 79-CurrentPass*TracksPerPass; CurrentEndTrack = max(0, CurrentStartTrack-TracksPerPass+1); } Track = CurrentStartTrack; WipeProgress(Window, 79-CurrentStartTrack); for(i=0; i<5; i++) if (INACTUALDEST(i) || i == ActualSource) SendAndLockMsg(i, INIT, i == ActualSource && Date && !Formatting && CurrentPass == 0 ? -1 : CurrentStartTrack); BufferUsed = DEST(ActualSource); break; case 'S': Stop(); break; case ESC: case 'Q': Fuga = 1; break; case 'B': case 'V': case 'D': case 'A': case 'N': case 'T': if (!G) break; if (Class == VANILLAKEY) ToggleGadget(Window, G); i = ((G->Flags & SELECTED) != 0); switch(Op) { case 'V': Verify = i; break; case 'D': Date = i; break; case 'A': break; case 'N': UseFFS = i; break; case 'T': if (i) { if (!OpenVoice()) SelectGadget(Window, G, FALSE); } else CloseVoice(); break; case 'B': if (i) { if (Passes = OpenDiskTask(4)) { Buffer = 1; } else { SelectGadget(Window, G, FALSE); Acknowledge("Not enough memory."); } } else { CloseDiskTask(4); Buffer = 0; } if (!Buffer) { Passes = 1; } TracksPerPass = 80/Passes+(Passes==3); CurrentPass = Passes-1; break; } break; case '0': case '1': case '2': case '3': Op -= '0'; if (!G) break; if (Class == VANILLAKEY) ToggleGadget(Window, G); if ((i = (G->Flags & SELECTED)) && OpenDiskTask(Op)) { if (Source == Op) break; if (Source>=0) { SelectGadget(Window, GAddr(DF0S)+Source, FALSE); if (!INDEST(Source)) CloseDiskTask(Source); } Source = Op; } else { SelectGadget(Window, G, FALSE); if (i) Acknowledge(NoDiskMsg); if (!INDEST(Op)) CloseDiskTask(Op); if (Op == Source) Source = -1; } break; case '4': case '5': case '6': case '7': Op -= '4'; if (!G) break; if (Class == VANILLAKEY) ToggleGadget(Window, G); if ((i = (G->Flags & SELECTED)) && OpenDiskTask(Op)) Dest |= DEST(Op); else { Dest &= ~DEST(Op); SelectGadget(Window, G, FALSE); if (i) Acknowledge(NoDiskMsg); if (Op != Source) CloseDiskTask(Op); } break; } break; } } if (Message) { MsgLocked[Message->im_ID] = 0; switch(Message->im_Action) { case INIT: if (Message->im_ID == ActualSource && Message->im_RC == NOT_DOS) Acknowledge("This is not a DOS disk."); break; case READ_TRACK: if (Copying && Message->im_RC == READ_ERROR && ProblemsWithUnit("Read", Message->im_ID, Message->im_n)) { ReSendAndLockMsg(Message); break; } if (FatalErrors(Message)) Stop(); b = Message->im_p; BufferTrack = Message->im_n; BufferUsed = ActualDest; if (Formatting && Message->im_n>=0) MakeFormatData(Message->im_n, b = FormatBuffer, UseFFS); break; case WRITE_TRACK: case WRITE_AND_VERIFY_TRACK: if (Copying && ((Message->im_RC == WRITE_ERROR && ProblemsWithUnit("Write", Message->im_ID, Message->im_n)) || (Message->im_RC == VERIFY_ERROR && ProblemsWithUnit("Verify", Message->im_ID, Message->im_n)))) { ReSendAndLockMsg(Message); break; } if (FatalErrors(Message)) Stop(); break; case STOP_MOTOR: if (Message->im_ID == ActualSource) { BufferUsed = ActualDest; BufferTrack = CurrentEndTrack-1; } else if (NoLockedMsgs(ActualDest)) { EnableGadgets(Window, ALLMASK); UpdateProgress(Window); if (FormatBuffer) { FreeMem(FormatBuffer, TRACKSIZE); FormatBuffer = NULL; } Copying = 0; } break; } if (NoLockedMsgs(ActualDest)) for(i=0; i<5; i++) if (DEST(i) & BufferUsed & ActualDest) { BufferUsed &= ~DEST(i); if ((Date || Formatting) && BufferTrack==40) UpdateRootBlock(b); CopyBuffer(b, i, BufferTrack % TracksPerPass); SendAndLockMsg(i, (Copying && BufferTrack>=CurrentEndTrack) ? (Verify ? WRITE_AND_VERIFY_TRACK : WRITE_TRACK) : STOP_MOTOR, BufferTrack); } if (!BufferUsed) { if (Copying && BufferTrack>=CurrentEndTrack) DrawProgress(Window, 79-BufferTrack, Buffer && Copying == 'G' ? 1 : 3); BufferUsed = DEST(ActualSource); if (BufferTrack == CurrentEndTrack+4) Beep(3000); if (Copying && BufferTrack == CurrentEndTrack-1) { Beep(4000); if (!Buffer || Formatting) Say("Operation completed."); else Say("Pass completed."); } } if (!MsgLocked[ActualSource] && (BufferUsed & DEST(ActualSource)) && Track >= CurrentEndTrack-1) { SendAndLockMsg(ActualSource, (Copying && Track>=CurrentEndTrack) ? READ_TRACK : STOP_MOTOR, Track--); } } } while(Msg || Message); if (Fuga && NoLockedMsgs(ALLMSGS)) break; Wait(1 << Window->UserPort->mp_SigBit | 1 << MainPort->mp_SigBit); } GameOver: if (Window) CloseWindow(Window); if (IntuitionBase) CloseLibrary((void *)IntuitionBase); if (GfxBase) CloseLibrary((void *)GfxBase); for(i=0; i<5; i++) CloseDiskTask(i); CloseAudio(); CloseVoice(); ClosePorts(); }