home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff377.lzh / Formatter / Formatter.c < prev    next >
C/C++ Source or Header  |  1990-10-10  |  46KB  |  1,975 lines

  1. /* $Revision Header * Header built automatically - do not edit! *************
  2.  *
  3.  *    (C) Copyright 1990 by MXM
  4.  *
  5.  *    Name .....: Formatter.c
  6.  *    Created ..: Thursday 31-May-90 19:49
  7.  *    Revision .: 4
  8.  *
  9.  *    Date            Author          Comment
  10.  *    =========       ========        ====================
  11.  *    02-Aug-90       Olsen           Gadget/menu coordination fixed
  12.  *    24-Jul-90       Olsen           Removed bug in formatting routine,
  13.  *                                    added disk validation break,
  14.  *                                    fixed the bootblock checksum
  15.  *    08-Jul-90       Olsen           Sped up the formatting process
  16.  *    08-Jun-90       Olsen           Added the menu
  17.  *    08-Jun-90       Olsen           Fixed some bugs
  18.  *    31-May-90       Olsen           Created this file!
  19.  *
  20.  ****************************************************************************
  21.  *
  22.  *    This file contains the main routines used by Formatter.c
  23.  *
  24.  * $Revision Header ********************************************************/
  25.  
  26.     /* Prototypes for this module. */
  27.  
  28. BYTE    FindDevice(char *DevName);
  29. VOID    RefreshGadget(struct Window *Window,struct Gadget *Gadget,BYTE Colour);
  30. VOID    ClearPort(VOID);
  31. VOID    AdjustClass(VOID);
  32. VOID    ConvertString(char *ToString,char *FromString);
  33. ULONG    FixBlockSum(ULONG *Array);
  34. ULONG    FixBootSum(ULONG *Array);
  35. VOID    SetBitmapBlock(ULONG *BitmapData,SHORT Block,BYTE SetFlag);
  36. VOID    ClearBlock(ULONG *Block);
  37. VOID    Inhibit(char *Drive,BYTE Bool);
  38. BYTE    CompareTracks(ULONG *Track1,ULONG *Track2);
  39. BYTE    DiskRead(BYTE Track);
  40. BYTE    DiskWrite(ULONG Offset,BYTE Track);
  41. BYTE    DiskFormat(BYTE Track);
  42. BYTE    Formatter(char *DiskName);
  43. VOID    CentreWindow(struct NewWindow *New,USHORT OffsetX,USHORT OffsetY);
  44. VOID    DecrementUsage(VOID);
  45. VOID    CloseAll(BYTE ReturnCode);
  46. VOID    OpenAll(VOID);
  47. LONG    Strlen(VOID *String);
  48. VOID    Strcpy(VOID *Dest,VOID *Source);
  49. VOID    main(int argc,char **argv);
  50.  
  51.     /* Assembly language string routines. */
  52.  
  53. #pragma regcall(Strlen(a0))
  54. #pragma regcall(Strcpy(a0,a1))
  55.  
  56.     /* Window interaction. */
  57.  
  58. struct Window        *Window;
  59. struct IntuiMessage    *Massage;
  60. ULONG             Class,Code;
  61. BYTE             GadgetID;
  62.  
  63.     /* Global information port. */
  64.  
  65. struct FormatterPort    *GlobalPort;
  66.  
  67. #define PORTNAME     "Formatter"
  68.  
  69.     /* Disk interaction. */
  70.  
  71. struct MsgPort        *DiskPort;
  72. struct IOExtTD        *DiskRequest;
  73. struct MsgPort        *TimePort;
  74. struct timerequest    *TimeRequest;
  75. ULONG            *DiskTrack,*CheckTrack,*RootTrack;
  76. BYTE             DriveUnit = 0;
  77. ULONG             OffsetTable[NUMCYLS];
  78.  
  79.     /* Debug flag. */
  80.  
  81. BYTE             DebugFlag = FALSE;
  82.  
  83.     /* Boolean flags. */
  84.  
  85. #define AutoStart    (FormatGadget[4] . Flags & SELECTED)
  86. #define Verify        (FormatGadget[5] . Flags & SELECTED)
  87. #define Fast        (FormatGadget[6] . Flags & SELECTED)
  88. #define Install        (FormatGadget[7] . Flags & SELECTED)
  89. #define FFS        (FormatMenuItem[6].Flags & CHECKED)
  90.  
  91.     /* Arp CLI info. */
  92.  
  93. char *CLI_Template    = "Drive,NAME/K,F=FAST/S,I=INSTALL/S,V=VERIFY/S,A=AUTOSTART/S,FFS/S,DEBUG/S";
  94. char *CLI_Help        = "\nUsage: Formatter [DF0: | DF1: | DF2: | DF3:] [Name]\n                 [FAST] [INSTALL] [VERIFY] [AUTOSTART] [FFS]\n";
  95.  
  96.     /* Argument vector offsets. */
  97.  
  98. #define ARG_DRIVE    1
  99. #define ARG_NAME    2
  100. #define ARG_FAST    3
  101. #define ARG_INSTALL    4
  102. #define ARG_VERIFY    5
  103. #define ARG_AUTOSTART    6
  104. #define ARG_FFS        7
  105. #define ARG_DEBUG    8
  106.  
  107.     /* Default font for text rendering. */
  108.  
  109. struct TextAttr DefaultFont =
  110. {
  111.     (STRPTR)"topaz.font",
  112.     8,
  113.     FS_NORMAL,
  114.     FPF_ROMFONT
  115. };
  116.  
  117. struct TextAttr BoldFont =
  118. {
  119.     (STRPTR)"topaz.font",
  120.     8,
  121.     FSF_BOLD,
  122.     FPF_ROMFONT
  123. };
  124.  
  125.     /* A whole lot of intuition & graphics data. */
  126.  
  127. struct IntuiText InfoText = { 1,0,JAM1,0,25,&DefaultFont,(UBYTE *)"                                        ",NULL };
  128.  
  129. struct IntuiText FormatIntTxt[10] =
  130. {
  131.     {1,0,0, 21,2,&DefaultFont,(UBYTE *)"DF0:",        NULL},
  132.     {1,0,0, 21,2,&DefaultFont,(UBYTE *)"DF1:",        NULL},
  133.     {1,0,0, 21,2,&DefaultFont,(UBYTE *)"DF2:",        NULL},
  134.     {1,0,0, 21,2,&DefaultFont,(UBYTE *)"DF3:",        NULL},
  135.     {1,0,0, 20,2,&DefaultFont,(UBYTE *)"Auto start",    NULL},
  136.     {1,0,0, 12,2,&DefaultFont,(UBYTE *)"Verify Write",    NULL},
  137.     {1,0,0, 16,2,&DefaultFont,(UBYTE *)"Fast format",    NULL},
  138.     {1,0,0, 12,2,&DefaultFont,(UBYTE *)"Install Disk",    NULL},
  139.     {1,0,0, 12,9,&DefaultFont,(UBYTE *)NULL,        NULL},
  140.     {1,0,0,-48,0,&DefaultFont,(UBYTE *)"Name:",        NULL}
  141. };
  142.  
  143. UBYTE FormatText[32],UndoFormatText[32];
  144.  
  145. struct StringInfo FormatStringInfo = { FormatText,UndoFormatText,0,32,32,0,0,0,0,NULL,NULL,NULL };
  146.  
  147. SHORT FormatBorderData[] =
  148. {
  149.     -1,-1, 74,-1, 74,12,-1,12,-1,-1,
  150.     -2,-1, 75,-1, 75,12,-2,12,-2,-1,
  151.     -1,-1, 74,-1, 74,12,-1,12,-1,-1,
  152.     -2,-1, 75,-1, 75,12,-2,12,-2,-1,
  153.     -1,-1, 74,-1, 74,12,-1,12,-1,-1,
  154.     -2,-1, 75,-1, 75,12,-2,12,-2,-1,
  155.     -1,-1, 74,-1, 74,12,-1,12,-1,-1,
  156.     -2,-1, 75,-1, 75,12,-2,12,-2,-1,
  157.     -1,-1,120,-1,120,12,-1,12,-1,-1,
  158.     -2,-1,121,-1,121,12,-2,12,-2,-1,
  159.     -1,-1,120,-1,120,12,-1,12,-1,-1,
  160.     -2,-1,121,-1,121,12,-2,12,-2,-1,
  161.     -1,-1,120,-1,120,12,-1,12,-1,-1,
  162.     -2,-1,121,-1,121,12,-2,12,-2,-1,
  163.     -1,-1,120,-1,120,12,-1,12,-1,-1,
  164.     -2,-1,121,-1,121,12,-2,12,-2,-1,
  165.     -2,-1, 66,-1, 66,27,-2,27,-2,-1,
  166.     -1,-1, 65,-1, 65,27,-1,27,-1,-1,
  167.     -1,-1,256,-1,256, 8,-1, 8,-1,-1,
  168.     -2,-1,257,-1,257, 8,-2, 8,-2,-1
  169. };
  170.  
  171. struct Border FormatBorder[] =
  172. {
  173.     {0,0,1,0,0,5,&FormatBorderData[  0],&FormatBorder[ 1]},
  174.     {0,0,1,0,0,5,&FormatBorderData[ 10],NULL},
  175.     {0,0,1,0,0,5,&FormatBorderData[ 20],&FormatBorder[ 3]},
  176.     {0,0,1,0,0,5,&FormatBorderData[ 30],NULL},
  177.     {0,0,1,0,0,5,&FormatBorderData[ 40],&FormatBorder[ 5]},
  178.     {0,0,1,0,0,5,&FormatBorderData[ 50],NULL},
  179.     {0,0,1,0,0,5,&FormatBorderData[ 60],&FormatBorder[ 7]},
  180.     {0,0,1,0,0,5,&FormatBorderData[ 70],NULL},
  181.     {0,0,1,0,0,5,&FormatBorderData[ 80],&FormatBorder[ 9]},
  182.     {0,0,1,0,0,5,&FormatBorderData[ 90],NULL},
  183.     {0,0,1,0,0,5,&FormatBorderData[100],&FormatBorder[11]},
  184.     {0,0,1,0,0,5,&FormatBorderData[110],NULL},
  185.     {0,0,1,0,0,5,&FormatBorderData[120],&FormatBorder[13]},
  186.     {0,0,1,0,0,5,&FormatBorderData[130],NULL},
  187.     {0,0,1,0,0,5,&FormatBorderData[140],&FormatBorder[15]},
  188.     {0,0,1,0,0,5,&FormatBorderData[150],NULL},
  189.     {0,0,1,0,0,5,&FormatBorderData[160],&FormatBorder[17]},
  190.     {0,0,1,0,0,5,&FormatBorderData[170],NULL},
  191.     {0,0,1,0,0,5,&FormatBorderData[180],&FormatBorder[19]},
  192.     {0,0,1,0,0,5,&FormatBorderData[190],NULL}
  193. };
  194.  
  195. #define IMMEDIATE    (RELVERIFY | GADGIMMEDIATE)
  196. #define TOGGLE        (RELVERIFY | GADGIMMEDIATE | TOGGLESELECT)
  197.  
  198. struct Gadget FormatGadget[10] =
  199. {
  200.     {&FormatGadget[1],  6,67, 74,12,0,IMMEDIATE,    BOOLGADGET,    (APTR)&FormatBorder[ 0],NULL,&FormatIntTxt[0],NULL,NULL,            0,NULL},
  201.     {&FormatGadget[2], 87,67, 74,12,0,IMMEDIATE,    BOOLGADGET,    (APTR)&FormatBorder[ 2],NULL,&FormatIntTxt[1],NULL,NULL,            1,NULL},
  202.     {&FormatGadget[3],168,67, 74,12,0,IMMEDIATE,    BOOLGADGET,    (APTR)&FormatBorder[ 4],NULL,&FormatIntTxt[2],NULL,NULL,            2,NULL},
  203.     {&FormatGadget[4],249,67, 74,12,0,IMMEDIATE,    BOOLGADGET,    (APTR)&FormatBorder[ 6],NULL,&FormatIntTxt[3],NULL,NULL,            3,NULL},
  204.     {&FormatGadget[5],  6,37,120,12,0,TOGGLE,    BOOLGADGET,    (APTR)&FormatBorder[ 8],NULL,&FormatIntTxt[4],NULL,NULL,            4,NULL},
  205.     {&FormatGadget[6],  6,52,120,12,0,TOGGLE,    BOOLGADGET,    (APTR)&FormatBorder[10],NULL,&FormatIntTxt[5],NULL,NULL,            5,NULL},
  206.     {&FormatGadget[7],132,37,120,12,0,TOGGLE,    BOOLGADGET,    (APTR)&FormatBorder[12],NULL,&FormatIntTxt[6],NULL,NULL,            6,NULL},
  207.     {&FormatGadget[8],132,52,120,12,0,TOGGLE,    BOOLGADGET,    (APTR)&FormatBorder[14],NULL,&FormatIntTxt[7],NULL,NULL,            7,NULL},
  208.     {&FormatGadget[9],258,37, 65,27,0,IMMEDIATE,    BOOLGADGET,    (APTR)&FormatBorder[16],NULL,&FormatIntTxt[8],NULL,NULL,            8,NULL},
  209.     {NULL,             67,82,256, 8,0,IMMEDIATE,    STRGADGET,    (APTR)&FormatBorder[18],NULL,&FormatIntTxt[9],NULL,(APTR)&FormatStringInfo,    9,NULL}
  210. };
  211.  
  212. UBYTE *FormatInfoText[2] =
  213. {
  214.     (UBYTE *)"  Start formatting",
  215.     (UBYTE *)"  Stop formatting"
  216. };
  217.  
  218. struct IntuiText FormatMenuIntTxt[16] =
  219. {
  220.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  About...",            NULL},
  221.     {0,0,0,2,1,&BoldFont   ,(UBYTE *)"_______________________",    NULL},
  222.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Auto start",        NULL},
  223.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Fast format",        NULL},
  224.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Verify write",        NULL},
  225.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Install disk",        NULL},
  226.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Use FFS",            NULL},
  227.     {0,0,0,2,1,&BoldFont   ,(UBYTE *)"_______________________",    NULL},
  228.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Drive DF0:",        NULL},
  229.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Drive DF1:",        NULL},
  230.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Drive DF2:",        NULL},
  231.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Drive DF3:",        NULL},
  232.     {0,0,0,2,1,&BoldFont   ,(UBYTE *)"_______________________",    NULL},
  233.     {0,0,0,2,1,&DefaultFont,NULL,                    NULL},
  234.     {0,0,0,2,1,&BoldFont   ,(UBYTE *)"_______________________",    NULL},
  235.     {0,0,0,2,1,&DefaultFont,(UBYTE *)"  Quit",            NULL}
  236. };
  237.  
  238. struct MenuItem FormatMenuItem[16] =
  239. {
  240.     {&FormatMenuItem[ 1],0,  0,188,10, 86, 0,(APTR)&FormatMenuIntTxt[ 0],NULL,63,NULL,~0L},
  241.     {&FormatMenuItem[ 2],0,  3,188,10,210, 0,(APTR)&FormatMenuIntTxt[ 1],NULL, 0,NULL,~0L},
  242.     {&FormatMenuItem[ 3],0, 13,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 2],NULL,65,NULL,~0L},
  243.     {&FormatMenuItem[ 4],0, 23,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 3],NULL,70,NULL,~0L},
  244.     {&FormatMenuItem[ 5],0, 33,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 4],NULL,86,NULL,~0L},
  245.     {&FormatMenuItem[ 6],0, 43,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 5],NULL,73,NULL,~0L},
  246.     {&FormatMenuItem[ 7],0, 53,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 6],NULL,85,NULL,~0L},
  247.     {&FormatMenuItem[ 8],0, 56,188,10,210, 0,(APTR)&FormatMenuIntTxt[ 7],NULL, 0,NULL,~0L},
  248.     {&FormatMenuItem[ 9],0, 66,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 8],NULL,49,NULL,~0L},
  249.     {&FormatMenuItem[10],0, 76,188,10, 95, 0,(APTR)&FormatMenuIntTxt[ 9],NULL,50,NULL,~0L},
  250.     {&FormatMenuItem[11],0, 86,188,10, 95, 0,(APTR)&FormatMenuIntTxt[10],NULL,51,NULL,~0L},
  251.     {&FormatMenuItem[12],0, 96,188,10, 95, 0,(APTR)&FormatMenuIntTxt[11],NULL,52,NULL,~0L},
  252.     {&FormatMenuItem[13],0, 99,188,10,210, 0,(APTR)&FormatMenuIntTxt[12],NULL, 0,NULL,~0L},
  253.     {&FormatMenuItem[14],0,109,188,10, 86, 0,(APTR)&FormatMenuIntTxt[13],NULL,83,NULL,~0L},
  254.     {&FormatMenuItem[15],0,112,188,10,210, 0,(APTR)&FormatMenuIntTxt[14],NULL, 0,NULL,~0L},
  255.     {NULL               ,0,122,188,10, 86, 0,(APTR)&FormatMenuIntTxt[15],NULL,81,NULL,~0L}
  256. };
  257.  
  258. struct Menu FormatMenu = {NULL,0,0,112,0,257,"Formatter 2.4",&FormatMenuItem[0]};
  259.  
  260. struct IntuiText ReqIntTxt[9] =
  261. {
  262.     {2,0,0,  3, 3,&DefaultFont,(UBYTE *)"Copy me, I wish to travel!",    NULL},
  263.     {2,0,0, 10, 5,&BoldFont,   (UBYTE *)"Formatter 2.4a",            &ReqIntTxt[2]},
  264.     {3,0,0,127, 5,&DefaultFont,(UBYTE *)"© Copyright 1990 by MXM",        &ReqIntTxt[3]},
  265.     {0,0,0,127,17,&DefaultFont,(UBYTE *)"Olaf Barthel",            &ReqIntTxt[4]},
  266.     {0,0,0,127,25,&DefaultFont,(UBYTE *)"Brabeckstrasse 35",        &ReqIntTxt[5]},
  267.     {0,0,0,127,33,&DefaultFont,(UBYTE *)"D-3000 Hannover 71",        &ReqIntTxt[6]},
  268.     {2,0,0, 67,17,&DefaultFont,(UBYTE *)"Author",                &ReqIntTxt[7]},
  269.     {2,0,0, 11,45,&DefaultFont,(UBYTE *)"Shareware fee",            &ReqIntTxt[8]},
  270.     {0,0,0,127,45,&DefaultFont,(UBYTE *)"7 US$ or DM 15,-",            NULL}
  271. };
  272.  
  273. SHORT ReqBorderData[] =
  274. {
  275.     -1,-1,214,-1,214,14,-1,14,-1,-1,
  276.     -2,-1,215,-1,215,14,-2,14,-2,-1,
  277.      0, 0,311, 0,311,75, 0,75, 0, 0,
  278.      0, 0,311, 0,311,75, 0,75, 0, 0
  279. };
  280.  
  281. struct Border ReqBorder[] =
  282. {
  283.     {0,0,2,0,0,5,&ReqBorderData[ 0],&ReqBorder[1]},
  284.     {0,0,2,0,0,5,&ReqBorderData[10],NULL},
  285.     {4,2,0,0,0,5,&ReqBorderData[20],&ReqBorder[3]},
  286.     {5,2,0,0,0,5,&ReqBorderData[30],NULL}
  287. };
  288.  
  289. struct Gadget ReqGadget = {NULL,53,58,214,14,0,3,4097,(APTR)&ReqBorder[0],NULL,&ReqIntTxt[0],NULL,NULL,0,NULL};
  290.  
  291. struct Requester Req;
  292.  
  293.     /* A very new window (well, sort of). */
  294.  
  295. struct NewWindow NewWindow =
  296. {
  297.     0,0,
  298.     330,93,
  299.     -1,-1,
  300.     CLOSEWINDOW | GADGETUP | MOUSEBUTTONS | MENUPICK | VANILLAKEY,
  301.     WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | ACTIVATE | RMBTRAP,
  302.     (struct Gadget *)&FormatGadget[0],
  303.     (struct Image *)NULL,
  304.     (STRPTR)"Formatter 2.4a",
  305.     (struct Screen *)NULL,
  306.     (struct BitMap *)NULL,
  307.     0,0,
  308.     0,0,
  309.     WBENCHSCREEN
  310. };
  311.  
  312.     /* The track indicator (run dump). */
  313.  
  314. USHORT PanelMap[220] =
  315. {
  316.     0x78F0,0x0000,0x0030,0xF000,0x0000,0x78F0,0x0000,0x0078,
  317.     0xF000,0x0000,0xC0F0,0x0000,0x00FC,0xF000,0x0000,0x78F0,
  318.     0x0000,0x00FC,0xF000,0x0000,0xCD98,0x0000,0x0071,0x9800,
  319.     0x0000,0xCD98,0x0000,0x00CD,0x9800,0x0000,0xD998,0x0000,
  320.     0x00C1,0x9800,0x0000,0xC198,0x0000,0x000D,0x9800,0x0000,
  321.     0xCD98,0x0000,0x0031,0x9800,0x0000,0x1998,0x0000,0x0019,
  322.     0x9800,0x0000,0xD998,0x0000,0x00F9,0x9800,0x0000,0xF998,
  323.     0x0000,0x0019,0x9800,0x0000,0xCD98,0x0000,0x0031,0x9800,
  324.     0x0000,0x3198,0x0000,0x00CD,0x9800,0x0000,0xFD98,0x0000,
  325.     0x000D,0x9800,0x0000,0xCD98,0x0000,0x0031,0x9800,0x0000,
  326.     0x78F0,0x0000,0x0078,0xF000,0x0000,0xFCF0,0x0000,0x0078,
  327.     0xF000,0x0000,0x18F0,0x0000,0x00F8,0xF000,0x0000,0x78F0,
  328.     0x0000,0x0030,0xF000,0x0000,0x0000,0x0000,0x0000,0x0000,
  329.     0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  330.     0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  331.     0xC000,0x0000,0x00C0,0x0000,0x0000,0xC000,0x0000,0x00C0,
  332.     0x0000,0x0000,0xC000,0x0000,0x00C0,0x0000,0x0000,0xC000,
  333.     0x0000,0x00C0,0x0000,0x0000,0xC000,0x0000,0x00C0,0x0000,
  334.     0x0000,0xC000,0x0000,0x00C0,0x0000,0x0000,0xC000,0x0000,
  335.     0x00C0,0x0000,0x0000,0xC000,0x0000,0x00C0,0x0000,0x0000,
  336.     0xC000,0x0C00,0x00C0,0x000C,0x0000,0xC000,0x0C00,0x00C0,
  337.     0x000C,0x0000,0xC000,0x0C00,0x00C0,0x000C,0x0000,0xC000,
  338.     0x0C00,0x00C0,0x000C,0x0000,0xC000,0x0C00,0x00C0,0x000C,
  339.     0x0000,0xC000,0x0C00,0x00C0,0x000C,0x0000,0xC000,0x0C00,
  340.     0x00C0,0x000C,0x0000,0xC000,0x0C00,0x00C0,0x000C,0x0000,
  341.     0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
  342.     0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
  343.     0xFFFF,0xFFFF,0xFFFF,0xFFFF
  344. };
  345.  
  346.     /* The track indicator (the image structure). */
  347.  
  348. struct Image PanelImage =
  349. {
  350.     0,0,
  351.     320,11,1,
  352.     (USHORT *)&PanelMap[0],
  353.     0x01,0x00,
  354.     (struct Image *)NULL
  355. };
  356.  
  357.     /* A rectangular shape. */
  358.  
  359. struct Image Box =
  360. {
  361.     0,0,4,12,2,
  362.     (USHORT *)NULL,
  363.     0,0x03,
  364.     (struct Image *)NULL
  365. };
  366.  
  367.     /* A standard disk bootblock (as used by the install command, only the
  368.      * DOS disk ID and the checksum are missing).
  369.      */
  370.  
  371. ULONG Standard[13] =
  372. {
  373.     0x00000000,0x00000000,0x00000370,0x43FA0018,0x4EAEFFA0,0x4A80670A,
  374.     0x20402068,0x00167000,0x4E7570FF,0x60FA646F,0x732E6C69,0x62726172,
  375.     0x79000000
  376. };
  377.  
  378.     /* Some embedded assembly language code. */
  379.  
  380. #asm
  381.     PUBLIC    _Strlen
  382.     PUBLIC    _Strcpy
  383.  
  384. ;    Simple strlen routine.
  385.  
  386. _Strlen:
  387.     MOVEQ    #0,D0        ; Reset length counter
  388. 1$    TST.B    (A0)+        ; Check for end
  389.     BEQ.S    2$        ; Found it
  390.     ADDQ    #1,D0        ; Increment length counter
  391.     BRA.S    1$        ; Test again
  392. 2$    RTS
  393.  
  394. ;    Simple strcpy routine
  395.  
  396. _Strcpy:
  397.     TST.B    (A1)        ; Check source byte
  398.     BEQ.S    1$        ; Found the end?
  399.     MOVE.B    (A1)+,(A0)+    ; Copy the byte over
  400.     BRA.S    _Strcpy        ; Test again
  401. 1$    MOVE.B    #0,(A0)        ; Null termination
  402.     RTS
  403. #endasm
  404.  
  405.     /* FindDevice():
  406.      *
  407.      *    Tries to discover a device name in the linked list
  408.      *    of device nodes to be found in DosLibrary.
  409.      */
  410.  
  411. BYTE
  412. FindDevice(char *DevName)
  413. {
  414.     extern struct DosLibrary    *DOSBase;
  415.     char                *Pointer,Name[257];
  416.     register struct DeviceNode    *DevInfo;
  417.     struct RootNode            *RootNode = (struct RootNode *)DOSBase -> dl_Root;
  418.     SHORT                 i;
  419.  
  420.         /* Knock the rest of the system out. */
  421.  
  422.     Forbid();
  423.  
  424.         /* The starting point. */
  425.  
  426.     DevInfo = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(RootNode -> rn_Info)) -> di_DevInfo);
  427.  
  428.         /* As long as it's valid. */
  429.  
  430.     while(DevInfo)
  431.     {
  432.             /* Is it a device and does it have a file handler task attached? */
  433.  
  434.         if(DevInfo -> dn_Type == DLT_DEVICE && DevInfo -> dn_Task)
  435.         {
  436.                 /* Convert the name. */
  437.  
  438.             Pointer = (char *)BADDR(DevInfo -> dn_Name);
  439.  
  440.             for(i = 0 ; i < Pointer[0] ; i++)
  441.                 Name[i] = Pointer[i + 1];
  442.  
  443.             Name[Pointer[0]    ] = ':';
  444.             Name[Pointer[0] + 1] = 0;
  445.  
  446.                 /* Compare the names. */
  447.  
  448.             if(!Strcmp(Name,DevName))
  449.             {
  450.                 Permit();
  451.                 return(TRUE);
  452.             }
  453.         }
  454.  
  455.             /* Check next entry. */
  456.  
  457.         DevInfo = (struct DeviceNode *)BADDR(DevInfo -> dn_Next);
  458.     }
  459.  
  460.     Permit();
  461.  
  462.     return(FALSE);
  463. }
  464.  
  465.     /* RefreshGadget():
  466.      *
  467.      *    Clears the background of a gadget and refreshes it.
  468.      */
  469.  
  470. VOID
  471. RefreshGadget(struct Window *Window,struct Gadget *Gadget,BYTE Colour)
  472. {
  473.     struct Gadget    *NextGadget = Gadget -> NextGadget;
  474.     BYTE         FgPen = Window -> RPort -> FgPen;
  475.  
  476.         /* Clear the background. */
  477.  
  478.     SetAPen(Window -> RPort,Colour);
  479.     RectFill(Window -> RPort,Gadget -> LeftEdge,Gadget -> TopEdge,Gadget -> LeftEdge + Gadget -> Width - 1,Gadget -> TopEdge + Gadget -> Height - 1);
  480.     SetAPen(Window -> RPort,FgPen);
  481.  
  482.         /* Refresh a single gadget. */
  483.  
  484.     Gadget -> NextGadget = NULL;
  485.     RefreshGadgets(Gadget,Window,NULL);
  486.     Gadget -> NextGadget = NextGadget;
  487. }
  488.  
  489.     /* ClearPort():
  490.      *
  491.      *    Removes all pending messages from the Window UserPort.
  492.      */
  493.  
  494. VOID
  495. ClearPort()
  496. {
  497.     while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  498.         ReplyMsg(Massage);
  499.  
  500.     Class    = NULL;
  501.     Code    = NULL;
  502. }
  503.  
  504.     /* PerformRequest():
  505.      *
  506.      *    Display the information requester in the
  507.      *    formatter window.
  508.      */
  509.  
  510. VOID
  511. PerformRequest()
  512. {
  513.     InitRequester(&Req);
  514.  
  515.         /* I don't know how it happened, but the main
  516.          * window is an odd number of rows wide, which
  517.          * makes it somehow difficult to cover the
  518.          * window properly with the requester.
  519.          */
  520.  
  521.     Req . LeftEdge    = 4;
  522.     Req . TopEdge    = 11;
  523.     Req . Width    = 324;
  524.     Req . Height    = 80;
  525.     Req . BackFill    = 1;
  526.     Req . Flags    = NOISYREQ | SIMPLEREQ;
  527.     Req . ReqGadget    = &ReqGadget;
  528.     Req . ReqBorder    = &ReqBorder[2];
  529.     Req . ReqText    = &ReqIntTxt[1];
  530.  
  531.         /* Now, this gets really boring. */
  532.  
  533.     if(Request(&Req,Window))
  534.     {
  535.         FOREVER
  536.         {
  537.             WaitPort(Window -> UserPort);
  538.  
  539.             while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  540.             {
  541.                 Class = Massage -> Class;
  542.  
  543.                 if(Class == GADGETUP || Class == VANILLAKEY)
  544.                 {
  545.                     EndRequest(&Req,Window);
  546.                     return;
  547.                 }
  548.             }
  549.         }
  550.     }
  551. }
  552.  
  553.     /* AdjustClass():
  554.      *
  555.      *    Formatter is controlled both by menu and by gadgets;
  556.      *    the following routine links both interfaces.
  557.      */
  558.  
  559. VOID
  560. AdjustClass()
  561. {
  562.     USHORT    MenuNum = Code;
  563.     BYTE    i;
  564.  
  565.         /* Truly selected a menu item? */
  566.  
  567.     if(MenuNum != MENUNULL)
  568.         Class = GADGETUP;
  569.     else
  570.         return;
  571.  
  572.         /* Get the menu item behind the Intuition menu number. */
  573.  
  574.     while(MenuNum != MENUNULL)
  575.     {
  576.         if(MENUNUM(MenuNum) == 0)
  577.         {
  578.             switch(ITEMNUM(MenuNum))
  579.             {
  580.                 case 0:    PerformRequest();
  581.                     Class = NULL;
  582.                     break;
  583.  
  584.                 case 2:    FormatGadget[4] . Flags ^= SELECTED;
  585.                     RefreshGadget(Window,&FormatGadget[4],0);
  586.                     Class = NULL;
  587.                     break;
  588.  
  589.                 case 3:    FormatGadget[6] . Flags ^= SELECTED;
  590.                     RefreshGadget(Window,&FormatGadget[6],0);
  591.                     Class = NULL;
  592.                     break;
  593.  
  594.                 case 4:    FormatGadget[5] . Flags ^= SELECTED;
  595.                     RefreshGadget(Window,&FormatGadget[5],0);
  596.                     Class = NULL;
  597.                     break;
  598.  
  599.                 case 5:    FormatGadget[7] . Flags ^= SELECTED;
  600.                     RefreshGadget(Window,&FormatGadget[7],0);
  601.                     Class = NULL;
  602.                     break;
  603.  
  604.                 case 8:
  605.                 case 9:
  606.                 case 10:
  607.                 case 11:for(i = 0 ; i < 4 ; i++)
  608.                         if((FormatMenuItem[8 + i] . Flags & ITEMENABLED) && 8 + i != ITEMNUM(MenuNum))
  609.                             FormatMenuItem[8 + i] . Flags &= ~CHECKED;
  610.  
  611.                     GadgetID = ITEMNUM(MenuNum) - 8;
  612.                     break;
  613.  
  614.                 case 13:GadgetID = 8;
  615.                     break;
  616.  
  617.                 case 15:Class = CLOSEWINDOW;
  618.                     break;
  619.  
  620.                 default:Class = NULL;
  621.                     break;
  622.             }
  623.         }
  624.  
  625.         MenuNum = ((struct MenuItem *)ItemAddress(&FormatMenu,MenuNum)) -> NextSelect;
  626.     }
  627. }
  628.  
  629.     /* ConvertString():
  630.      *
  631.      *    Turn a 'C' string into a BCPL string.
  632.      */
  633.  
  634. VOID
  635. ConvertString(char *ToString,char *FromString)
  636. {
  637.     *ToString++ = Strlen(FromString);
  638.  
  639.     while(*FromString)
  640.         *ToString++ = *FromString++;
  641. }
  642.  
  643.     /* FixBlockSum():
  644.      *
  645.      *    Calculate the checksum for a DOS disk block.
  646.      *    The checksum itself is the complement of the sum
  647.      *    of all the longwords contained in a track.
  648.      */
  649.  
  650. ULONG
  651. FixBlockSum(ULONG *Array)
  652. {
  653.     ULONG    Sum = 0;
  654.     UBYTE    i = 128;
  655.  
  656.     while(i--)
  657.         Sum += Array[i];
  658.  
  659.     return(-Sum);
  660. }
  661.  
  662.     /* FixBootSum(ULONG *Array):
  663.      *
  664.      *    Calculates the checksum for a disk bootblock, which
  665.      *    unfortunately uses an algorithm different from
  666.      *    FixBlockSum.
  667.      */
  668.  
  669. ULONG
  670. FixBootSum(ULONG *Array)
  671. {
  672.     ULONG    Sum = 0,LastSum;
  673.     UBYTE    i = 128;
  674.  
  675.     while(i--)
  676.     {
  677.         LastSum = Sum;
  678.  
  679.         if((Sum += Array[i]) < LastSum)
  680.             Sum++;
  681.     }
  682.  
  683.     return(~Sum);
  684. }
  685.  
  686.     /* SetBitmapBlock():
  687.      *
  688.      *    Marks a block in the disk bitmap (bit by bit).
  689.      *    A standard bitmap consists of fifty-five longwords
  690.      *    in which each bit represents a disk block. If a
  691.      *    bit is set, a block is unused. A cleared bit indicates
  692.      *    an allocated block.
  693.      */
  694.  
  695. VOID
  696. SetBitmapBlock(ULONG *BitmapData,SHORT Block,BYTE SetFlag)
  697. {
  698.     if(SetFlag)
  699.         BitmapData[Block / 32] &= ~(1 << (Block % 32));
  700.     else
  701.         BitmapData[Block / 32] |=  (1 << (Block % 32));
  702. }
  703.  
  704.     /* ClearBlock():
  705.      *
  706.      *    Set the contents of disk block to zero. It takes less
  707.      *    time to clear the longwords contained in a disk track
  708.      *    than to clear the single bytes.
  709.      */
  710.  
  711. VOID
  712. ClearBlock(ULONG *Block)
  713. {
  714.     UBYTE Offset = 128;
  715.  
  716.     while(Offset--)
  717.         *Block++ = 0;
  718. }
  719.  
  720.     /* Inhibit():
  721.      *
  722.      *    Toggle the activity of the disk validator. We send
  723.      *    a DOS packet to the file handler task telling it
  724.      *    to disable or to enable the disk validator.
  725.      */
  726.  
  727. VOID
  728. Inhibit(char *Drive,BYTE Bool)
  729. {
  730.     struct MsgPort    *Handler;
  731.     LONG         Args[7];
  732.  
  733.     if(Bool)
  734.         Args[0] = DOSTRUE;
  735.     else
  736.         Args[0] = DOSFALSE;
  737.  
  738.     if(Handler = DeviceProc(Drive))
  739.         SendPacket(ACTION_INHIBIT,Args,Handler);
  740. }
  741.  
  742.     /* CompareTracks():
  743.      *
  744.      *    Check if two disk blocks are equal.
  745.      */
  746.  
  747. BYTE
  748. CompareTracks(ULONG *Track1,ULONG *Track2)
  749. {
  750.     SHORT Size = (NUMSECS * NUMHEADS * TD_SECTOR) >> 2;
  751.  
  752.     while(Size--)
  753.         if(*Track1++ != *Track2++)
  754.             return(FALSE);
  755.  
  756.     return(TRUE);
  757. }
  758.  
  759.     /* DiskRead():
  760.      *
  761.      *    Read a track from disk and compare it with the
  762.      *    data in the buffer.
  763.      */
  764.  
  765. BYTE
  766. DiskRead(BYTE Track)
  767. {
  768.     SHORT    Position = 4 + Box . Width * Track;
  769.     BYTE    Error;
  770.  
  771.         /* Initialize the request. */
  772.  
  773.     DiskRequest -> iotd_Req . io_Offset = OffsetTable[Track];
  774.  
  775.         /* Start the request. */
  776.  
  777.     BeginIO(DiskRequest);
  778.  
  779.         /* Move up one track. */
  780.  
  781.     Box . PlaneOnOff = 3;
  782.     DrawImage(Window -> RPort,&Box,Position,23);
  783.  
  784.         /* News in the mail? */
  785.  
  786.     if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  787.     {
  788.         Class        = Massage -> Class;
  789.         Code        = Massage -> Code;
  790.         GadgetID    = ((struct Gadget *)Massage -> IAddress) -> GadgetID;
  791.  
  792.         ReplyMsg(Massage);
  793.  
  794.         if(Class == MENUPICK)
  795.             AdjustClass();
  796.  
  797.         if(Class == GADGETUP)
  798.         {
  799.                 /* Stop formatting? */
  800.  
  801.             if(GadgetID == 8)
  802.             {
  803.                 /* Wait for request to be replied. */
  804.  
  805.                 WaitIO(DiskRequest);
  806.  
  807.                 /* Format aborted. */
  808.  
  809.                 return(-42);
  810.             }
  811.  
  812.             if(GadgetID == 4)
  813.                 FormatMenuItem[2] . Flags ^= CHECKED;
  814.  
  815.             if(GadgetID == 6)
  816.                 FormatMenuItem[3] . Flags ^= CHECKED;
  817.  
  818.             if(GadgetID == 5)
  819.                 FormatMenuItem[4] . Flags ^= CHECKED;
  820.  
  821.             if(GadgetID == 7)
  822.                 FormatMenuItem[5] . Flags ^= CHECKED;
  823.         }
  824.     }
  825.  
  826.         /* Trouble? */
  827.  
  828.     if(Error = WaitIO(DiskRequest))
  829.         return(Error);
  830.  
  831.         /* Are both buffers equal? */
  832.  
  833.     if(Track == 40)
  834.     {
  835.         if(!CompareTracks(DiskTrack,RootTrack))
  836.         {
  837.             Box . PlaneOnOff = 2;
  838.             DrawImage(Window -> RPort,&Box,Position,23);
  839.  
  840.             if(DebugFlag)
  841.             {
  842.                 char HelpName[20];
  843.                 BPTR Help;
  844.  
  845.                 SPrintf(HelpName,"RAM:SRCTRACK%02ld",Track);
  846.  
  847.                 if(Help = Open(HelpName,MODE_NEWFILE))
  848.                 {
  849.                     Write(Help,RootTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  850.                     Close(Help);
  851.                 }
  852.  
  853.                 SPrintf(HelpName,"RAM:DSTTRACK%02ld",Track);
  854.  
  855.                 if(Help = Open(HelpName,MODE_NEWFILE))
  856.                 {
  857.                     Write(Help,DiskTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  858.                     Close(Help);
  859.                 }
  860.             }
  861.  
  862.             /* Verification error. */
  863.  
  864.             return(-43);
  865.         }
  866.     }
  867.     else
  868.     {
  869.         if(!CompareTracks(DiskTrack,CheckTrack))
  870.         {
  871.             Box . PlaneOnOff = 2;
  872.             DrawImage(Window -> RPort,&Box,Position,23);
  873.  
  874.             /* Verification error. */
  875.  
  876.             if(DebugFlag)
  877.             {
  878.                 char HelpName[20];
  879.                 BPTR Help;
  880.  
  881.                 SPrintf(HelpName,"RAM:SRCTRACK%02ld",Track);
  882.  
  883.                 if(Help = Open(HelpName,MODE_NEWFILE))
  884.                 {
  885.                     Write(Help,CheckTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  886.                     Close(Help);
  887.                 }
  888.  
  889.                 SPrintf(HelpName,"RAM:DSTTRACK%02ld",Track);
  890.  
  891.                 if(Help = Open(HelpName,MODE_NEWFILE))
  892.                 {
  893.                     Write(Help,DiskTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  894.                     Close(Help);
  895.                 }
  896.             }
  897.  
  898.             return(-43);
  899.         }
  900.     }
  901.  
  902.     return(0);
  903. }
  904.  
  905.     /* DiskWrite():
  906.      *
  907.      *    Write two blocks to disk.
  908.      */
  909.  
  910. BYTE
  911. DiskWrite(ULONG Offset,BYTE Track)
  912. {
  913.     SHORT     Position = 4 + Box . Width * Track;
  914.     ULONG    *OriginalTrack = DiskRequest -> iotd_Req . io_Data;
  915.     BYTE     Error;
  916.  
  917.         /* Initialize the request. */
  918.  
  919.     DiskRequest -> iotd_Req . io_Command    = ETD_WRITE;
  920.     DiskRequest -> iotd_Req . io_Length    = TD_SECTOR * 2;
  921.     DiskRequest -> iotd_Req . io_Offset    = Offset;
  922.  
  923.         /* Start the request. */
  924.  
  925.     BeginIO(DiskRequest);
  926.  
  927.         /* Move up one track. */
  928.  
  929.     Box . PlaneOnOff = 1;
  930.     DrawImage(Window -> RPort,&Box,Position,23);
  931.  
  932.         /* News in the mail? */
  933.  
  934.     if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  935.     {
  936.         Class        = Massage -> Class;
  937.         Code        = Massage -> Code;
  938.         GadgetID    = ((struct Gadget *)Massage -> IAddress) -> GadgetID;
  939.  
  940.         ReplyMsg(Massage);
  941.  
  942.         if(Class == MENUPICK)
  943.             AdjustClass();
  944.  
  945.         if(Class == GADGETUP)
  946.         {
  947.                 /* Stop formatting? */
  948.  
  949.             if(GadgetID == 8)
  950.             {
  951.                 /* Wait for request to be replied. */
  952.  
  953.                 WaitIO(DiskRequest);
  954.  
  955.                 /* Format aborted. */
  956.  
  957.                 return(-42);
  958.             }
  959.  
  960.             if(GadgetID == 4)
  961.                 FormatMenuItem[2] . Flags ^= CHECKED;
  962.  
  963.             if(GadgetID == 6)
  964.                 FormatMenuItem[3] . Flags ^= CHECKED;
  965.  
  966.             if(GadgetID == 5)
  967.                 FormatMenuItem[4] . Flags ^= CHECKED;
  968.  
  969.             if(GadgetID == 7)
  970.                 FormatMenuItem[5] . Flags ^= CHECKED;
  971.         }
  972.     }
  973.  
  974.         /* Trouble? */
  975.  
  976.     if(Error = WaitIO(DiskRequest))
  977.         return(Error);
  978.  
  979.         /* Verify the data? */
  980.  
  981.     if(Verify)
  982.     {
  983.             /* Make sure the buffer has been written. */
  984.  
  985.         DiskRequest -> iotd_Req . io_Command = ETD_UPDATE;
  986.         DoIO(DiskRequest);
  987.  
  988.             /* Reread the buffer. */
  989.  
  990.         DiskRequest -> iotd_Req . io_Command    = ETD_READ;
  991.         DiskRequest -> iotd_Req . io_Data    = (APTR)CheckTrack;
  992.  
  993.         if(Error = DoIO(DiskRequest))
  994.             return(Error);
  995.  
  996.             /* Are both buffers equal? */
  997.  
  998.         if(!CompareTracks(OriginalTrack,CheckTrack))
  999.         {
  1000.             Box . PlaneOnOff = 2;
  1001.             DrawImage(Window -> RPort,&Box,Position,23);
  1002.  
  1003.             /* Verification error. */
  1004.  
  1005.             return(-43);
  1006.         }
  1007.  
  1008.         Box . PlaneOnOff = 3;
  1009.         DrawImage(Window -> RPort,&Box,Position,23);
  1010.     }
  1011.  
  1012.     return(0);
  1013. }
  1014.  
  1015.     /* DiskFormat():
  1016.      *
  1017.      *    Perform a disk write access.
  1018.      */
  1019.  
  1020. BYTE
  1021. DiskFormat(BYTE Track)
  1022. {
  1023.     BYTE Error;
  1024.  
  1025.         /* Initialize the request. */
  1026.  
  1027.     DiskRequest -> iotd_Req . io_Offset = OffsetTable[Track];
  1028.  
  1029.     if(Track == 40)
  1030.         DiskRequest -> iotd_Req . io_Data = (APTR)RootTrack;
  1031.  
  1032.             /* Start the request. */
  1033.  
  1034.     BeginIO(DiskRequest);
  1035.  
  1036.         /* Move up one track. */
  1037.  
  1038.     Box . PlaneOnOff = 1;
  1039.     DrawImage(Window -> RPort,&Box,4 + Box . Width * Track,23);
  1040.  
  1041.         /* News in the mail? */
  1042.  
  1043.     if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1044.     {
  1045.         Class        = Massage -> Class;
  1046.         Code        = Massage -> Code;
  1047.         GadgetID    = ((struct Gadget *)Massage -> IAddress) -> GadgetID;
  1048.  
  1049.         ReplyMsg(Massage);
  1050.  
  1051.         if(Class == MENUPICK)
  1052.             AdjustClass();
  1053.  
  1054.         if(Class == GADGETUP)
  1055.         {
  1056.                 /* Stop formatting? */
  1057.  
  1058.             if(GadgetID == 8)
  1059.             {
  1060.                 /* Wait for request to be replied. */
  1061.  
  1062.                 WaitIO(DiskRequest);
  1063.  
  1064.                 if(Track == 40)
  1065.                     DiskRequest -> iotd_Req . io_Data = (APTR)DiskTrack;
  1066.  
  1067.                 /* Format aborted. */
  1068.  
  1069.                 return(-42);
  1070.             }
  1071.  
  1072.             if(GadgetID == 4)
  1073.                 FormatMenuItem[2] . Flags ^= CHECKED;
  1074.  
  1075.             if(GadgetID == 6)
  1076.                 FormatMenuItem[3] . Flags ^= CHECKED;
  1077.  
  1078.             if(GadgetID == 5)
  1079.                 FormatMenuItem[4] . Flags ^= CHECKED;
  1080.  
  1081.             if(GadgetID == 7)
  1082.                 FormatMenuItem[5] . Flags ^= CHECKED;
  1083.         }
  1084.     }
  1085.  
  1086.     Error = WaitIO(DiskRequest);
  1087.  
  1088.     if(Track == 40)
  1089.         DiskRequest -> iotd_Req . io_Data = (APTR)DiskTrack;
  1090.  
  1091.     return(Error);
  1092. }
  1093.  
  1094.     /* Formatter():
  1095.      *
  1096.      *    Format a disk drive, 3½" hardwired to the Amiga.
  1097.      */
  1098.  
  1099. BYTE
  1100. Formatter(char *DiskName)
  1101. {
  1102.     struct DosDirectory    *RootBlock;
  1103.     struct DosBitmap    *DosBitmap;
  1104.     BYTE             Error,GeneralError = FALSE;
  1105.     SHORT             i;
  1106.  
  1107.         /* Allocate both auxilary buffers. */
  1108.  
  1109.     if(CheckTrack = (ULONG *)AllocMem(NUMSECS * NUMHEADS * TD_SECTOR,MEMF_CHIP | MEMF_CLEAR))
  1110.     {
  1111.         if(DiskTrack = (ULONG *)AllocMem(NUMSECS * NUMHEADS * TD_SECTOR,MEMF_CHIP | MEMF_CLEAR))
  1112.         {
  1113.             if(RootTrack = (ULONG *)AllocMem(NUMSECS * NUMHEADS * TD_SECTOR,MEMF_CHIP | MEMF_CLEAR))
  1114.             {
  1115.                     /* It's a DOS disk. */
  1116.  
  1117.                 if(FFS)
  1118.                     CheckTrack[0] = DiskTrack[0] = ID_FFS_DISK;
  1119.                 else
  1120.                     CheckTrack[0] = DiskTrack[0] = ID_DOS_DISK;
  1121.  
  1122.                     /* Tie them to the buffer. */
  1123.  
  1124.                 RootBlock    = (struct DosDirectory *)RootTrack;
  1125.                 DosBitmap    = (struct DosBitmap *)((ULONG)RootTrack + TD_SECTOR);
  1126.  
  1127.                     /* Clear the root block. */
  1128.  
  1129.                 ClearBlock((ULONG *)RootBlock);
  1130.  
  1131.                     /* Initialize the defaults. */
  1132.  
  1133.                 RootBlock -> PrimaryType    = T_SHORT;
  1134.                 RootBlock -> SecondaryType    = ST_ROOT;
  1135.                 RootBlock -> HashTableSize    = 128 - 56;
  1136.                 RootBlock -> BitmapFlag        = DOSFALSE;
  1137.                 RootBlock -> BitmapPointers[0]    = (NUMTRACKS / 2) * NUMSECS + 1;
  1138.  
  1139.                     /* Set the date stamps. */
  1140.  
  1141.                 DateStamp(&RootBlock -> LastRootChange);
  1142.                 DateStamp(&RootBlock -> LastDiskChange);
  1143.                 DateStamp(&RootBlock -> CreationDate);
  1144.  
  1145.                     /* Copy the name string over. */
  1146.  
  1147.                 ConvertString(RootBlock -> DiskName,DiskName);
  1148.  
  1149.                     /* Calculate the block checksum. */
  1150.  
  1151.                 RootBlock -> CheckSum = FixBlockSum((ULONG *)RootBlock);
  1152.  
  1153.                     /* Clear the disk bitmap. */
  1154.  
  1155.                 ClearBlock((ULONG *)DosBitmap);
  1156.  
  1157.                     /* Mark all bitmap blocks as unused. */
  1158.  
  1159.                 for(i = 0 ; i < 55 ; i++)
  1160.                     DosBitmap -> BitmapData[i] = ~0L;
  1161.  
  1162.                     /* Mark two blocks as used (880 -> Root block, 881 -> Bitmap).
  1163.                      * Note that the first two blocks by default are reserved
  1164.                      * and, not being part of the bitmap itself, have to
  1165.                      * be skipped.
  1166.                      */
  1167.  
  1168.                 SetBitmapBlock(DosBitmap -> BitmapData,880 - 2,TRUE);
  1169.                 SetBitmapBlock(DosBitmap -> BitmapData,881 - 2,TRUE);
  1170.  
  1171.                     /* Calculate the block checksum. */
  1172.  
  1173.                 DosBitmap -> CheckSum = FixBlockSum((ULONG *)DosBitmap);
  1174.  
  1175.                     /* Is there a disk in the drive? */
  1176.  
  1177.                 DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1178.                 DoIO(DiskRequest);
  1179.  
  1180.                 if(!DiskRequest -> iotd_Req . io_Actual)
  1181.                 {
  1182.                         /* Is the disk write enabled? */
  1183.  
  1184.                     DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  1185.                     DoIO(DiskRequest);
  1186.  
  1187.                     if(!DiskRequest -> iotd_Req . io_Actual)
  1188.                     {
  1189.                             /* Get the disk change number. */
  1190.  
  1191.                         DiskRequest -> iotd_Req . io_Command = TD_CHANGENUM;
  1192.                         DoIO(DiskRequest);
  1193.  
  1194.                             /* Set the standard flags. */
  1195.  
  1196.                         DiskRequest -> iotd_Req . io_Flags    = 0;
  1197.                         DiskRequest -> iotd_Count        = DiskRequest -> iotd_Req . io_Actual;
  1198.  
  1199.                             /* Remove all messages. */
  1200.  
  1201.                         ClearPort();
  1202.  
  1203.                             /* Are we to format the whole disk? */
  1204.  
  1205.                         if(!Fast)
  1206.                         {
  1207.                             DiskRequest -> iotd_Req . io_Command    = ETD_FORMAT;
  1208.                             DiskRequest -> iotd_Req . io_Data    = (APTR)DiskTrack;
  1209.                             DiskRequest -> iotd_Req . io_Length    = NUMSECS * NUMHEADS * TD_SECTOR;
  1210.  
  1211.                             for(i = 0 ; i < NUMCYLS ; i++)
  1212.                                 if(Error = DiskFormat(i))
  1213.                                     break;
  1214.  
  1215.                             if(Verify && !Error)
  1216.                             {
  1217.                                 DiskRequest -> iotd_Req . io_Command = ETD_READ;
  1218.  
  1219.                                 for(i = NUMCYLS - 1 ; i >= 0 && Verify ; i--)
  1220.                                     if(Error = DiskRead(i))
  1221.                                         break;
  1222.                             }
  1223.                         }
  1224.  
  1225.                         if(!Error)
  1226.                         {
  1227.                             if(Install || Fast)
  1228.                             {
  1229.                                 ClearBlock(DiskTrack);
  1230.  
  1231.                                 if(FFS)
  1232.                                     DiskTrack[0] = ID_FFS_DISK;
  1233.                                 else
  1234.                                     DiskTrack[0] = ID_DOS_DISK;
  1235.  
  1236.                                     /* Take the standard boot block? */
  1237.  
  1238.                                 if(Install)
  1239.                                 {
  1240.                                     CopyMemQuick(Standard,DiskTrack,sizeof(Standard));
  1241.  
  1242.                                     if(FFS)
  1243.                                         DiskTrack[0] = ID_FFS_DISK;
  1244.                                     else
  1245.                                         DiskTrack[0] = ID_DOS_DISK;
  1246.  
  1247.                                     DiskTrack[1] = FixBootSum(DiskTrack);
  1248.                                 }
  1249.  
  1250.                                 DiskRequest -> iotd_Req . io_Data = (APTR)DiskTrack;
  1251.  
  1252.                                 if(Error = DiskWrite(0,0))
  1253.                                 {
  1254.                                     i = 0;
  1255.                                     goto WriteError;
  1256.                                 }
  1257.  
  1258.                                 if(Fast)
  1259.                                 {
  1260.                                     DiskRequest -> iotd_Req . io_Data = (APTR)RootTrack;
  1261.  
  1262.                                     if(Error = DiskWrite((NUMTRACKS / 2) * NUMSECS * TD_SECTOR,40))
  1263.                                     {
  1264.                                         i = 40;
  1265.                                         goto WriteError;
  1266.                                     }
  1267.                                 }
  1268.                             }
  1269.                         }
  1270.                         else
  1271.                         {
  1272. WriteError:                        if(Error > -42)
  1273.                                 SPrintf((char *)InfoText . IText,"Write error Nº%ld, track %ld!",Error,i);
  1274.                             else
  1275.                             {
  1276.                                 if(Error == -42)
  1277.                                     Strcpy((char *)InfoText . IText,"*** Format aborted ***");
  1278.                                 else
  1279.                                     SPrintf((char *)InfoText . IText,"Verification error on track %ld!",i);
  1280.                             }
  1281.  
  1282.                             GeneralError = TRUE;
  1283.                         }
  1284.  
  1285.                         DiskRequest -> iotd_Req . io_Command = ETD_UPDATE;
  1286.                         DoIO(DiskRequest);
  1287.  
  1288.                         DiskRequest -> iotd_Req . io_Command    = TD_MOTOR;
  1289.                         DiskRequest -> iotd_Req . io_Length    = 0;
  1290.  
  1291.                         DoIO(DiskRequest);
  1292.                     }
  1293.                     else
  1294.                     {
  1295.                         Strcpy(InfoText . IText,"Disk ist write protected!");
  1296.                         GeneralError = TRUE;
  1297.                     }
  1298.                 }
  1299.                 else
  1300.                 {
  1301.                     Strcpy(InfoText . IText,"No disk in drive!");
  1302.                     GeneralError = TRUE;
  1303.                 }
  1304.  
  1305.                 FreeMem(RootTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  1306.             }
  1307.  
  1308.             FreeMem(DiskTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  1309.         }
  1310.         else
  1311.         {
  1312.             Strcpy(InfoText . IText,"Out of memory!");
  1313.             GeneralError = TRUE;
  1314.         }
  1315.  
  1316.         FreeMem(CheckTrack,NUMSECS * NUMHEADS * TD_SECTOR);
  1317.     }
  1318.     else
  1319.     {
  1320.         Strcpy(InfoText . IText,"Out of memory!");
  1321.         GeneralError = TRUE;
  1322.     }
  1323.  
  1324.     ClearPort();
  1325.  
  1326.     return(GeneralError);
  1327. }
  1328.  
  1329.     /* CentreWindow():
  1330.      *
  1331.      *    Centre a new window under the mouse pointer. I didn't
  1332.      *    want to use the req.library function for this purpose
  1333.      *    and wrote my own special creation.
  1334.      */
  1335.  
  1336. VOID
  1337. CentreWindow(struct NewWindow *New,USHORT OffsetX,USHORT OffsetY)
  1338. {
  1339.     struct Screen PublicScreen;
  1340.  
  1341.         /* Get the screen data. */
  1342.  
  1343.     if(GetScreenData(&PublicScreen,sizeof(struct Screen),New -> Type,New -> Screen))
  1344.     {
  1345.             /* Put it under the mouse pointer. */
  1346.  
  1347.         New -> LeftEdge    = PublicScreen . MouseX - OffsetX;
  1348.         New -> TopEdge    = PublicScreen . MouseY - OffsetY;
  1349.  
  1350.             /* Adjust the x position. */
  1351.  
  1352.         while(New -> LeftEdge + New -> Width > PublicScreen . Width)
  1353.             New -> LeftEdge--;
  1354.  
  1355.         while(New -> LeftEdge < 0)
  1356.             New -> LeftEdge++;
  1357.  
  1358.             /* Adjust the y position. */
  1359.  
  1360.         while(New -> TopEdge + New -> Height > PublicScreen . Height)
  1361.             New -> TopEdge--;
  1362.  
  1363.         while(New -> TopEdge < 0)
  1364.             New -> TopEdge++;
  1365.     }
  1366. }
  1367.  
  1368.     /* DecrementUsage():
  1369.      *
  1370.      *    Decrement the number of currently running Formatters
  1371.      *    and remove the the MsgPort if the current Formatter is
  1372.      *    the last one to terminate.
  1373.      */
  1374.  
  1375. VOID
  1376. DecrementUsage()
  1377. {
  1378.     Forbid();
  1379.  
  1380.     if(!(--GlobalPort -> NumPrgs))
  1381.     {
  1382.         RemPort(&GlobalPort -> Port);
  1383.         FreeMem(GlobalPort,sizeof(struct FormatterPort));
  1384.     }
  1385.  
  1386.     Permit();
  1387. }
  1388.  
  1389.     /* CloseAll():
  1390.      *
  1391.      *    Closes devices and locks the shop.
  1392.      */
  1393.  
  1394. VOID
  1395. CloseAll(BYTE ReturnCode)
  1396. {
  1397.     if(TimeRequest)
  1398.     {
  1399.         if(TimeRequest -> tr_node . io_Device)
  1400.             CloseDevice(TimeRequest);
  1401.  
  1402.         DeleteExtIO(TimeRequest);
  1403.     }
  1404.  
  1405.     if(TimePort)
  1406.         DeletePort(TimePort);
  1407.  
  1408.     if(DiskRequest)
  1409.     {
  1410.         if(DiskRequest -> iotd_Req . io_Device)
  1411.             CloseDevice(DiskRequest);
  1412.  
  1413.         DeleteExtIO(DiskRequest);
  1414.     }
  1415.  
  1416.     if(DiskPort)
  1417.         DeletePort(DiskPort);
  1418.  
  1419.     if(Window)
  1420.     {
  1421.         ClearMenuStrip(Window);
  1422.         CloseWindow(Window);
  1423.     }
  1424.  
  1425.     exit(ReturnCode);
  1426. }
  1427.  
  1428.     /* OpenAll():
  1429.      *
  1430.      *    Opens the devices we need and also the window.
  1431.      */
  1432.  
  1433. VOID
  1434. OpenAll()
  1435. {
  1436.     if(!(TimePort = CreatePort(NULL,0)))
  1437.         CloseAll(RETURN_FAIL + 0);
  1438.  
  1439.     if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))))
  1440.         CloseAll(RETURN_FAIL + 1);
  1441.  
  1442.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0))
  1443.         CloseAll(RETURN_FAIL + 2);
  1444.  
  1445.     if(!(DiskPort = CreatePort(NULL,0)))
  1446.         CloseAll(RETURN_FAIL + 3);
  1447.  
  1448.     if(!(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD))))
  1449.         CloseAll(RETURN_FAIL + 4);
  1450.  
  1451.     if(OpenDevice(TD_NAME,DriveUnit,DiskRequest,0))
  1452.         CloseAll(RETURN_FAIL + 5);
  1453.  
  1454.     CentreWindow(&NewWindow,FormatGadget[8] . LeftEdge + (FormatGadget[8] . Width >> 1),FormatGadget[8] . TopEdge + (FormatGadget[8] . Height >> 1));
  1455.  
  1456.     if(!(Window = OpenWindow(&NewWindow)))
  1457.         CloseAll(RETURN_FAIL + 6);
  1458. }
  1459.  
  1460.     /* main():
  1461.      *
  1462.      *    That's where all the trouble starts.
  1463.      */
  1464.  
  1465. VOID
  1466. main(int argc,char **argv)
  1467. {
  1468.     static char    *Drive = "DFx:";
  1469.  
  1470.     BYTE         Error,OldUnit,DiskInDrive;
  1471.     ULONG         Time1,Time2,Dummy;
  1472.     SHORT         i;
  1473.  
  1474.         /* Try to find the global MsgPort. */
  1475.  
  1476.     Forbid();
  1477.  
  1478.     if(!(GlobalPort = (struct FormatterPort *)FindPort(PORTNAME)))
  1479.     {
  1480.             /* Didn't find it, create it now. */
  1481.  
  1482.         if(GlobalPort = (struct FormatterPort *)AllocMem(sizeof(struct FormatterPort),MEMF_PUBLIC | MEMF_CLEAR))
  1483.         {
  1484.             GlobalPort -> Port . mp_Node . ln_Name    = PORTNAME;
  1485.             GlobalPort -> Port . mp_Node . ln_Type    = NT_MSGPORT;
  1486.             GlobalPort -> Port . mp_Node . ln_Pri    = 1;
  1487.             GlobalPort -> Port . mp_Flags        = PA_IGNORE;
  1488.  
  1489.             AddPort(&GlobalPort -> Port);
  1490.         }
  1491.     }
  1492.  
  1493.         /* Increment the user count. */
  1494.  
  1495.     if(GlobalPort)
  1496.         GlobalPort -> NumPrgs++;
  1497.  
  1498.     Permit();
  1499.  
  1500.         /* Didn't create the port. */
  1501.  
  1502.     if(!GlobalPort)
  1503.     {
  1504.         if(argc)
  1505.             Printf("Formatter: Unable to create global MsgPort.\a\n");
  1506.  
  1507.         exit(RETURN_FAIL);
  1508.     }
  1509.  
  1510.         /* Do we expect CLI arguments? */
  1511.  
  1512.     if(argc > 1)
  1513.     {
  1514.         char TestString[5];
  1515.  
  1516.             /* Enable debug? */
  1517.  
  1518.         if(argv[ARG_DEBUG])
  1519.             DebugFlag = TRUE;
  1520.  
  1521.             /* Which disk drive? */
  1522.  
  1523.         if(argv[ARG_DRIVE])
  1524.         {
  1525.                 /* Does it match 'DFx:'? */
  1526.  
  1527.             if(Strlen(argv[ARG_DRIVE]) != 4)
  1528.             {
  1529.                 DecrementUsage();
  1530.  
  1531.                 Puts(CLI_Help);
  1532.                 exit(RETURN_WARN);
  1533.             }
  1534.  
  1535.             Strcpy(TestString,argv[ARG_DRIVE]);
  1536.  
  1537.             TestString[2] = 'x';
  1538.  
  1539.             if(Strcmp(Drive,TestString))
  1540.             {
  1541.                 DecrementUsage();
  1542.  
  1543.                 Puts(CLI_Help);
  1544.                 exit(RETURN_WARN);
  1545.             }
  1546.  
  1547.                 /* Can we find the device? */
  1548.  
  1549.             if(!FindDevice(argv[ARG_DRIVE]))
  1550.             {
  1551.                 DecrementUsage();
  1552.  
  1553.                 Printf("Formatter: Unable to find device '%s'.\a\n",argv[ARG_DRIVE]);
  1554.                 exit(RETURN_FAIL);
  1555.             }
  1556.  
  1557.             DriveUnit = argv[ARG_DRIVE][2] - '0';
  1558.         }
  1559.  
  1560.             /* Enable Auto-start? */
  1561.  
  1562.         if(argv[ARG_AUTOSTART])
  1563.         {
  1564.             FormatGadget[4] . Flags |= SELECTED;
  1565.             FormatMenuItem[2] . Flags |= CHECKED;
  1566.         }
  1567.  
  1568.             /* Enable verification? */
  1569.  
  1570.         if(argv[ARG_VERIFY])
  1571.         {
  1572.             FormatGadget[5] . Flags |= SELECTED;
  1573.             FormatMenuItem[4] . Flags |= CHECKED;
  1574.         }
  1575.  
  1576.             /* Enable fast format? */
  1577.  
  1578.         if(argv[ARG_FAST])
  1579.         {
  1580.             FormatGadget[6] . Flags |= SELECTED;
  1581.             FormatMenuItem[3] . Flags |= CHECKED;
  1582.         }
  1583.  
  1584.             /* Enable disk installation? */
  1585.  
  1586.         if(argv[ARG_INSTALL])
  1587.         {
  1588.             FormatGadget[7] . Flags |= SELECTED;
  1589.             FormatMenuItem[5] . Flags |= CHECKED;
  1590.         }
  1591.  
  1592.         if(argv[ARG_FFS])
  1593.             FormatMenuItem[6] . Flags |= CHECKED;
  1594.     }
  1595.  
  1596.     Forbid();
  1597.  
  1598.         /* Is the desired drive already occupied? */
  1599.  
  1600.     if(argc && argv[ARG_DRIVE])
  1601.     {
  1602.         if(GlobalPort -> DriveInUse[DriveUnit])
  1603.         {
  1604.             DecrementUsage();
  1605.  
  1606.             Permit();
  1607.  
  1608.             Printf("Formatter: A different Formatter task is currently using device '%s'.\a\n",argv[ARG_DRIVE]);
  1609.             exit(RETURN_FAIL);
  1610.         }    
  1611.         else
  1612.             GlobalPort -> DriveInUse[DriveUnit] = TRUE;
  1613.     }
  1614.     else
  1615.     {
  1616.             /* Try to find the first disk drive
  1617.              * currently not in use.
  1618.              */
  1619.  
  1620.         DriveUnit = -1;
  1621.  
  1622.         for(i = 0 ; i < 4 ; i++)
  1623.         {
  1624.             if(!GlobalPort -> DriveInUse[i])
  1625.             {
  1626.                 DriveUnit = i;
  1627.                 break;
  1628.             }
  1629.         }
  1630.  
  1631.             /* Didn't find an unused drive. */
  1632.  
  1633.         if(DriveUnit == -1)
  1634.         {
  1635.             DecrementUsage();
  1636.  
  1637.             Permit();
  1638.  
  1639.             DisplayBeep(NULL);
  1640.  
  1641.             exit(RETURN_FAIL);
  1642.         }
  1643.         else
  1644.             GlobalPort -> DriveInUse[DriveUnit] = TRUE;
  1645.     }
  1646.  
  1647.         /* Take which disk name? */
  1648.  
  1649.     if(argc)
  1650.         Strcpy(FormatText,(argv[ARG_NAME] ? argv[ARG_NAME] : "Blank"));
  1651.     else
  1652.         Strcpy(FormatText,"Blank");
  1653.  
  1654.         /* Set the start gadget text. */
  1655.  
  1656.     FormatIntTxt[8] . IText = (UBYTE *)"Start";
  1657.     FormatMenuIntTxt[13] . IText = FormatInfoText[0];
  1658.  
  1659.         /* Open the resources. */
  1660.  
  1661.     OpenAll();
  1662.  
  1663.         /* The timer request gets initialized. */
  1664.  
  1665.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1666.     TimeRequest -> tr_time . tv_micro    = MILLION / 2;
  1667.  
  1668.         /* Draw the track indicator. */
  1669.  
  1670.     DrawImage(Window -> RPort,&PanelImage,4,11);
  1671.  
  1672.         /* Mark the device gadgets. */
  1673.  
  1674.     for(i = 0 ; i < 4 ; i++)
  1675.     {
  1676.         Drive[2] = '0' + i;
  1677.  
  1678.         if(!FindDevice(Drive))
  1679.         {
  1680.             FormatGadget[i] . Flags |= GADGDISABLED;
  1681.             FormatMenuItem[8 + i] . Flags &= ~ITEMENABLED;
  1682.         }
  1683.         else
  1684.             FormatGadget[i] . Flags &= ~GADGDISABLED;
  1685.  
  1686.         if(i != DriveUnit)
  1687.             RefreshGadget(Window,&FormatGadget[i],0);
  1688.         else
  1689.         {
  1690.             RefreshGadget(Window,&FormatGadget[i],3);
  1691.             FormatMenuItem[8 + i] . Flags |= CHECKED;
  1692.         }
  1693.     }
  1694.  
  1695.         /* Build the track offset table. */
  1696.  
  1697.     for(i = 0 ; i < NUMCYLS ; i++)
  1698.         OffsetTable[i] = i * (NUMSECS * NUMHEADS * TD_SECTOR);
  1699.  
  1700.         /* Inhibit DFx:. */
  1701.  
  1702.     Drive[2] = '0' + DriveUnit;
  1703.     Inhibit(Drive,TRUE);
  1704.  
  1705.         /* Is there a disk in the drive? */
  1706.  
  1707.     DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1708.     DoIO(DiskRequest);
  1709.  
  1710.     DiskInDrive = DiskRequest -> iotd_Req . io_Actual;
  1711.  
  1712.         /* Enable the menu. */
  1713.  
  1714.     SetMenuStrip(Window,&FormatMenu);
  1715.  
  1716.     Window -> Flags &= ~RMBTRAP;
  1717.  
  1718.         /* Go into loop. */
  1719.  
  1720.     FOREVER
  1721.     {
  1722.             /* Wait half a second. */
  1723.  
  1724.         DoIO(TimeRequest);
  1725.  
  1726.             /* Auto-start enabled? */
  1727.  
  1728.         if(AutoStart)
  1729.         {
  1730.                 /* Has a disk been inserted? */
  1731.  
  1732.             DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1733.             DoIO(DiskRequest);
  1734.  
  1735.             if(!DiskRequest -> iotd_Req . io_Actual && (DiskRequest -> iotd_Req . io_Actual != DiskInDrive))
  1736.             {
  1737.                 DiskInDrive = DiskRequest -> iotd_Req . io_Actual;
  1738.  
  1739.                 GadgetID = 8;
  1740.  
  1741.                 Class = GADGETUP;
  1742.  
  1743.                 goto CheckClass;
  1744.             }
  1745.  
  1746.             DiskInDrive = DiskRequest -> iotd_Req . io_Actual;
  1747.         }
  1748.  
  1749.             /* News in the mail? */
  1750.  
  1751.         if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1752.         {
  1753.             Class        = Massage -> Class;
  1754.             Code        = Massage -> Code;
  1755.             GadgetID    = ((struct Gadget *)Massage -> IAddress) -> GadgetID;
  1756.  
  1757.             ReplyMsg(Massage);
  1758.  
  1759.                 /* Picked a menu item? */
  1760.  
  1761.             if(Class == MENUPICK)
  1762.                 AdjustClass();
  1763.  
  1764.                 /* Close the window. */
  1765.  
  1766.             if(Class == CLOSEWINDOW)
  1767.             {
  1768.                 Drive[2] = '0' + DriveUnit;
  1769.                 Inhibit(Drive,FALSE);
  1770.  
  1771.                 GlobalPort -> DriveInUse[DriveUnit] = FALSE;
  1772.  
  1773.                 DecrementUsage();
  1774.  
  1775.                 CloseAll(RETURN_OK);
  1776.             }
  1777.  
  1778.             Error = 0;
  1779.  
  1780.                 /* Check the gadgets. */
  1781.  
  1782. CheckClass:        if(Class == GADGETUP)
  1783.             {
  1784.                 switch(GadgetID)
  1785.                 {
  1786.                     case 0:
  1787.                     case 1:
  1788.                     case 2:
  1789.                     case 3:    OldUnit = DriveUnit;
  1790.  
  1791.                         Drive[2] = '0' + GadgetID;
  1792.  
  1793.                         if(!FindDevice(Drive))
  1794.                             break;
  1795.  
  1796.                         if(GadgetID != DriveUnit)
  1797.                         {
  1798.                             Forbid();
  1799.  
  1800.                             if(GlobalPort -> DriveInUse[GadgetID])
  1801.                             {
  1802.                                 Permit();
  1803.  
  1804.                                 DisplayBeep(Window -> WScreen);
  1805.                                 break;
  1806.                             }
  1807.  
  1808.                             GlobalPort -> DriveInUse[GadgetID] = TRUE;
  1809.                             GlobalPort -> DriveInUse[OldUnit]  = FALSE;
  1810.  
  1811.                             Permit();
  1812.  
  1813.                             Drive[2] = '0' + DriveUnit;
  1814.  
  1815.                             Inhibit(Drive,FALSE);
  1816.  
  1817.                             if(!Error)
  1818.                                 CloseDevice(DiskRequest);
  1819.  
  1820.                             DriveUnit = GadgetID;
  1821.  
  1822.                             for(i = 0 ; i < 4 ; i++)
  1823.                             {
  1824.                                 if(i != DriveUnit)
  1825.                                     RefreshGadget(Window,&FormatGadget[i],0);
  1826.                                 else
  1827.                                     RefreshGadget(Window,&FormatGadget[i],3);
  1828.  
  1829.                                 if((FormatMenuItem[8 + i] . Flags & ITEMENABLED) && i == DriveUnit)
  1830.                                     FormatMenuItem[8 + i] . Flags |= CHECKED;
  1831.                                 else
  1832.                                     FormatMenuItem[8 + i] . Flags &= ~CHECKED;
  1833.                             }
  1834.  
  1835.                             Drive[2] = '0' + DriveUnit;
  1836.                             Inhibit(Drive,TRUE);
  1837.  
  1838.                             if(Error = OpenDevice(TD_NAME,DriveUnit,DiskRequest,0))
  1839.                             {
  1840.                                 GadgetID = OldUnit;
  1841.                                 goto CheckClass;
  1842.                             }
  1843.                         }
  1844.  
  1845.                         break;
  1846.  
  1847.                     case 4:    FormatMenuItem[2] . Flags ^= CHECKED;
  1848.                         break;
  1849.  
  1850.                     case 5:    FormatMenuItem[4] . Flags ^= CHECKED;
  1851.                         break;
  1852.  
  1853.                     case 6:    FormatMenuItem[3] . Flags ^= CHECKED;
  1854.                         break;
  1855.  
  1856.                     case 7:    FormatMenuItem[5] . Flags ^= CHECKED;
  1857.                         break;
  1858.  
  1859.                     case 8:    DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1860.                         DoIO(DiskRequest);
  1861.  
  1862.                         DiskInDrive = DiskRequest -> iotd_Req . io_Actual;
  1863.  
  1864.                         FormatIntTxt[8] . IText = (UBYTE *)"Stop!";
  1865.                         RefreshGadget(Window,&FormatGadget[8],3);
  1866.  
  1867.                         for(i = 0 ; i < 4 ; i++)
  1868.                             FormatGadget[i] . Flags |= GADGDISABLED;
  1869.  
  1870.                         SetAPen(Window -> RPort,0);
  1871.                         RectFill(Window -> RPort,4,23,323,34);
  1872.                         SetAPen(Window -> RPort,1);
  1873.  
  1874.                         FormatGadget[4] . Flags |= GADGDISABLED;
  1875.                         RefreshGadget(Window,&FormatGadget[4],0);
  1876.                         FormatGadget[6] . Flags |= GADGDISABLED;
  1877.                         RefreshGadget(Window,&FormatGadget[6],0);
  1878.                         FormatGadget[9] . Flags |= GADGDISABLED;
  1879.                         RefreshGadget(Window,&FormatGadget[9],0);
  1880.  
  1881.                         FormatMenuItem[ 0] . Flags &= ~ITEMENABLED;
  1882.                         FormatMenuItem[ 2] . Flags &= ~ITEMENABLED;
  1883.                         FormatMenuItem[ 3] . Flags &= ~ITEMENABLED;
  1884.                         FormatMenuItem[ 6] . Flags &= ~ITEMENABLED;
  1885.                         FormatMenuItem[15] . Flags &= ~ITEMENABLED;
  1886.  
  1887.                         FormatMenuIntTxt[13] . IText = FormatInfoText[1];
  1888.  
  1889.                         for(i = 0 ; i < 4 ; i++)
  1890.                             FormatMenuItem[8 + i] . Flags &= ~ITEMENABLED;
  1891.  
  1892.                         CurrentTime(&Time1,&Dummy);
  1893.  
  1894.                         Error = Formatter((char *)FormatText);
  1895.  
  1896.                         CurrentTime(&Time2,&Dummy);
  1897.  
  1898.                         if(!Error)
  1899.                         {
  1900.                             Drive[2] = '0' + DriveUnit;
  1901.  
  1902.                             Inhibit(Drive,FALSE);
  1903.                             Delay(3 * TICKS_PER_SECOND);
  1904.                             Inhibit(Drive,TRUE);
  1905.                         }
  1906.  
  1907.                         FormatGadget[4] . Flags &= ~GADGDISABLED;
  1908.                         RefreshGadget(Window,&FormatGadget[4],0);
  1909.                         FormatGadget[6] . Flags &= ~GADGDISABLED;
  1910.                         RefreshGadget(Window,&FormatGadget[6],0);
  1911.                         FormatGadget[9] . Flags &= ~GADGDISABLED;
  1912.                         RefreshGadget(Window,&FormatGadget[9],0);
  1913.  
  1914.                         for(i = 0 ; i < 4 ; i++)
  1915.                         {
  1916.                             Drive[2] = '0' + i;
  1917.  
  1918.                             if(FindDevice(Drive))
  1919.                                 FormatMenuItem[8 + i] . Flags |= ITEMENABLED;
  1920.                         }
  1921.  
  1922.                         FormatMenuItem[ 0] . Flags |= ITEMENABLED;
  1923.                         FormatMenuItem[ 2] . Flags |= ITEMENABLED;
  1924.                         FormatMenuItem[ 3] . Flags |= ITEMENABLED;
  1925.                         FormatMenuItem[ 6] . Flags |= ITEMENABLED;
  1926.                         FormatMenuItem[15] . Flags |= ITEMENABLED;
  1927.  
  1928.                         FormatMenuIntTxt[13] . IText = FormatInfoText[0];
  1929.  
  1930.                         SetAPen(Window -> RPort,0);
  1931.                         RectFill(Window -> RPort,4,23,323,34);
  1932.                         SetAPen(Window -> RPort,1);
  1933.  
  1934.                         if(Error)
  1935.                         {
  1936.                             InfoText . LeftEdge = 4 + (320 - 8 * Strlen(InfoText . IText)) / 2;
  1937.                             PrintIText(Window -> RPort,&InfoText,0,0);
  1938.  
  1939.                             DisplayBeep(Window -> WScreen);
  1940.                         }
  1941.                         else
  1942.                         {
  1943.                             SPrintf((char *)InfoText . IText,"Formatting time %ld:%02ld",abs(Time2 - Time1) / 60,abs(Time2 - Time1) % 60);
  1944.  
  1945.                             InfoText . LeftEdge = 4 + (320 - 8 * Strlen(InfoText . IText)) / 2;
  1946.                             PrintIText(Window -> RPort,&InfoText,0,0);
  1947.                         }
  1948.  
  1949.                         for(i = 0 ; i < 4 ; i++)
  1950.                         {
  1951.                             Drive[2] = '0' + i;
  1952.  
  1953.                             if(!FindDevice(Drive))
  1954.                                 FormatGadget[i] . Flags |= GADGDISABLED;
  1955.                             else
  1956.                                 FormatGadget[i] . Flags &= ~GADGDISABLED;
  1957.  
  1958.                             if(i != DriveUnit)
  1959.                                 RefreshGadget(Window,&FormatGadget[i],0);
  1960.                             else
  1961.                                 RefreshGadget(Window,&FormatGadget[i],3);
  1962.                         }
  1963.  
  1964.                         FormatIntTxt[8] . IText = (UBYTE *)"Start";
  1965.                         RefreshGadget(Window,&FormatGadget[8],0);
  1966.  
  1967.                         break;
  1968.  
  1969.                     default:break;
  1970.                 }
  1971.             }
  1972.         }
  1973.     }
  1974. }
  1975.