home *** CD-ROM | disk | FTP | other *** search
/ ftp.update.uu.se / ftp.update.uu.se.2014.03.zip / ftp.update.uu.se / pub / rainbow / msdos / decus / RB139 / wut312sc.lzh / WUOVR.PAS < prev    next >
Pascal/Delphi Source File  |  1989-01-31  |  55KB  |  1,465 lines

  1. {** file wuovr.pas ⌐ Copyright 1986 Anthony G. Camas, all rights reserved **}
  2. { Intro - Displays "hello" message and disclaimer and waits for RESUME key }
  3. overlay procedure Intro;
  4. begin
  5.  
  6.   DrawBox (1, 1, 80, 24, AtNormal);
  7.   DrawBox (6, 10, 75, 19, AtBlink);
  8.   StartFastVideo (8, 3, AtDefault, 78, 23);
  9.   FVAttribute := AtBold;
  10.   Center (HeaderString);
  11.   FVAttribute := AtNormal;
  12.   WriteLn;
  13.   Center ('⌐ Copyright 1986 Anthony G. Camas');
  14.   Center ('⌐ Copyright 1989    Vinzenz Esser');
  15.   Center ('All Rights Reserved');
  16.   Center ('See source program for distribution and licensing information');
  17.   FVRow := 10; FVAttribute := AtBlink;
  18.   Center (' WARNING ');
  19.   FVAttribute := AtNormal;
  20.   Center ('This software  is provided  as is.    It comes with no warranties,');
  21.   Center ('expressed or implied,  including,  but not limited to, any implied');
  22.   Center ('warranties of merchantability or fitness for a particular purpose.');
  23.   Center ('Reasonable care has been taken  to ensure that this program works,');
  24.   Center ('but this cannot be warranted in any way,  especially since you got');
  25.   Center ('it for nothing.   You are expected to use it with reasonable care.');
  26.   Center ('Please be sure  to back up  the contents  of your hard disk before');
  27.   Center ('attempting  to use this program  to format or partition your disk.');
  28.   FVRow := 21; FVAttribute := AtBold;
  29.   Center ('Press RESUME to continue');
  30.   Center ('or press EXIT to return to MS-DOS');
  31.   WaitForResume;
  32.  
  33. end {Intro};
  34.  
  35. { PrPart - Print (display) current partitioning and other info about disk}
  36. overlay procedure PrPart;
  37. type
  38.   ModeType = (FirstMode, GeneralInfo, OpSystems, Partitions, BadSectors,
  39.               LastMode);
  40. var
  41.   Mode     :ModeType;
  42.   I, J, K  :Integer;
  43.   DontDisplay :Boolean;
  44. begin
  45.  
  46.   { Read HOM/OSN/DPD blocks; if this fails, a message will have been displayed
  47.     already, so just exit }
  48.   if not ReadMajorBlocks then Exit;
  49.  
  50.   Mode := Succ(FirstMode);
  51.   DontDisplay := False;
  52.  
  53.   { This loop continues until exit is requested }
  54.  
  55.   repeat {Until mode = LastMode}
  56.     { Display an appropriate screen based on the mode we are in }
  57.     If not DontDisplay then case Mode of
  58.     GeneralInfo: begin
  59.       DrawOutline;
  60.       StartFastVideo (3, 2, AtBold, 78, 23);
  61.       WITH HOMBlock.HOM DO
  62.       BEGIN
  63.         WriteFastLn ('-- DISK INFORMATION --');
  64.         FVAttribute := AtDefault;
  65.         PrintGeneralDiskInfo;
  66.         if (AutoBoot = $FF) or (BootTrack = 0) then
  67.           WriteFastLn ('No Auto Boot configured')
  68.         else
  69.         begin
  70.           WriteFastLn (Concat ('Auto Boot configured for Track ',
  71.                                Hex4Digit (BootTrack),
  72.                                'H, logical drive ',
  73.                                Chr(AutoBoot+Ord('A')-1)));
  74.         end;
  75.       end;
  76.       WriteLn;
  77.       FVAttribute := AtBold;
  78.       WriteFastLn ('NEXT SCREEN = operating system information');
  79.       WriteFastLn ('MAIN SCREEN = main menu');
  80.      end;
  81.     OpSystems: begin
  82.       DrawOutline;
  83.       StartFastVideo (3, 2, AtBold, 78, 23);
  84.       WITH OSNBlock.OSN DO
  85.       begin
  86.         WriteFastLn ('-- OPERATING SYSTEMS --');
  87.         FVAttribute := AtDefault;
  88.         For I := 0 to 30 DO
  89.           If ORD(Entry[I][0]) <> 0 then WriteLn (I:2,'  ',Entry[I]);
  90.       end;
  91.       WriteLn;
  92.       FVAttribute := AtBold;
  93.       WriteFastLn ('PREV SCREEN = general disk information');
  94.       WriteFastLn ('NEXT SCREEN = partitioning information');
  95.       WriteFastLn ('MAIN SCREEN = main menu');
  96.      end;
  97.     Partitions: begin
  98.       DrawOutline;
  99.       StartFastVideo (3, 2, AtBold, 78, 23);
  100.       WITH DPDBlock.DPD DO
  101.       begin
  102.         WriteFastLn ('-- DEFINED PARTITIONS --');
  103.         FVAttribute := AtDefault;
  104.         WriteLn;
  105.         WriteFastLn ('Start   End   Total              Part');
  106.         WriteFastLn ('Track  Track  Tracks    Size     Name      Drive    O/S            Boot');
  107.         WriteLn;
  108.         For I := 1 to EntryCount DO
  109.           WITH Entry[I] DO
  110.           begin
  111.             Write (' '); WriteHex4 (FirstTrack);
  112.             Write ('   '); WriteHex4 (LastTrack);
  113.             Write ('   '); WriteHex4 (LastTrack-FirstTrack+1);
  114.             Write ('  ');
  115.             Write (((LastTrack-FirstTrack+1) * 8.0 / 1024.0):7:3, 'MB  ');
  116.             For J := 0 to 7 do
  117.               If Name[J] >= ' ' then Write (Name[J]) else Write (' ');
  118.             Write ('     ', Chr(LogicalUnit+Ord('A')-1), ':   ',
  119.                    OSNBlock.OSN.Entry[OSNIndex], '   ');
  120.             IF FirstTrack = HOMBlock.HOM.BootTrack then Write ('*');
  121.             WriteLn;
  122.           end;
  123.           WriteLn;
  124.       end;
  125.       FVAttribute := AtBold;
  126.       WriteFastLn ('PREV SCREEN = operating system information');
  127.       WriteFastLn ('NEXT SCREEN = bad sector information');
  128.       WriteFastLn ('MAIN SCREEN = main menu');
  129.      end;
  130.     BadSectors: begin
  131.       DrawOutline;
  132.       StartFastVideo (3, 2, AtBold, 78, 23);
  133.       WriteFastLn ('-- BAD SECTORS (TRACK/SECTOR; HEX ADDRESSES) --');
  134.       FVRow := 21; FVAttribute := AtBlinkBold;
  135.       WriteFastLn ('Please wait...');
  136.       FVAttribute := AtDefault;
  137.       WriteLn;
  138.       K := 0; { Count of bad sectors }
  139.       For I := 0 to ((HOMBlock.HOM.Cylinders * HOMBlock.HOM.Surfaces) - 1) do
  140.         If SectorTable[I].Num <> 0 then
  141.           For J := 1 to 16 do
  142.             If SectorIsBad (I, J) then
  143.             begin
  144.               if K < 128 then
  145.               begin
  146.                 FVColumn := (K div 16)*9 + 5;
  147.                 FVRow := (K mod 16) + 4;
  148.                 WriteFast (Concat (Hex4Digit(I), '/', Hex2Digit(J)));
  149.               end;
  150.               K := K + 1;
  151.             end;
  152.      {end..end}
  153.       FVRow := 21;  FVColumn := 3;  FVAttribute := AtNormal;
  154.       WriteLn ('Total bad sectors: ', K);
  155.       FVAttribute := AtBold;
  156.       WriteFastLn ('PREV SCREEN = partitioning information');
  157.       WriteFastLn ('MAIN SCREEN = main menu');
  158.      end;
  159.     end;
  160.  
  161.     { If display was supressed, restore it }
  162.     DontDisplay := False;
  163.  
  164.     K := (RawChar and CapsLockMask);
  165.     Case K of
  166.      NextScreenKeyCode:
  167.       if Succ(Mode) = LastMode then DontDisplay := True else Mode := Succ(Mode);
  168.      PrevScreenKeyCode:
  169.       if Pred(Mode) = FirstMode then DontDisplay := True else Mode := Pred(Mode);
  170.      BackspaceKeyCode:
  171.       If Pred(Mode) = FirstMode then Mode := LastMode else Mode := Pred(Mode);
  172.      ReturnKeyCode:
  173.       Mode := Succ(Mode);
  174.      MainScreenKeyCode:
  175.       Mode := LastMode;
  176.      else
  177.       DontDisplay := True;
  178.     end;
  179.     { "DontDisplay" flag was set to true if there was some kind of an error.
  180.       Ring the bell in this case and then iterate. }
  181.     if DontDisplay then Write(^G);
  182.   until mode = LastMode;
  183. end {PrPart};
  184.  
  185. { FormatAndInitialize - Format and initialize disk. }
  186. overlay procedure FormatAndInitialize (MainMenuFunc :MenuFunction);
  187. Const
  188.   StructureDataFileName = 'WUTILDSK.DAT';
  189.   PriBootFileName = 'PREBOOT.LDX';
  190.   SecBootFileName = 'SECBOOT.LDX';
  191. Type
  192.   StructureDataFileRecord = Record
  193.     Name        :Str35;
  194.     HOMBlock    :SectorBlock
  195.   end;
  196. Var
  197.   PriBootFileSpec,
  198.   SecBootFileSpec,
  199.   StructureDataFileSpec :Str255;
  200.   PriBootFile,
  201.   SecBootFile           :File;
  202.   StructureDataFile     :File of StructureDataFileRecord;
  203.   I, J                  :Integer;
  204.   StructureDataRecord   :StructureDataFileRecord;
  205.   DiskTypeNames         :Array [0..25] of Str35;
  206.   NumDiskTypes          :Integer;
  207.   Trk                   :Integer;
  208.   Sec                   :Byte;
  209.   TrackDisplay          :Str4;
  210.   ZeroesData,
  211.   OnesData              :SectorBlock;
  212.   FormattingMode        :MenuFunction;
  213.  
  214.   {sub}Procedure CantFind (Name :Str80);
  215.   begin
  216.     DrawOutline;
  217.     Write (^G);
  218.     FVRow := 10;  FVAttribute := AtBold;
  219.     Center (Concat ('Cannot locate file ', Name));
  220.     WriteLn;
  221.     FVAttribute := AtDefault;
  222.     Center ('This file is required in order to perform this function.');
  223.     Center ('It must reside in your current working directory or in');
  224.     Center ('a directory in your PATH list.');
  225.     WriteLn;
  226.     Center ('See your WUTIL documentation for more information.');
  227.     WriteLn;
  228.     FVAttribute := AtBold;
  229.     Center ('Press any key to continue');
  230.     I := RawChar;
  231.   end {CantFind};
  232.  
  233.   {sub}function GetDiskData :Boolean;
  234.   type
  235.     EntryModeType = (FirstEntryMode, Description, TCode, NumCyl, NumSurf,
  236.                      Precomp, StRate, AltTracks, LastEntryMode);
  237.   var
  238.     I, J :Integer;
  239.     Trk  :Integer;
  240.     Sec  :Byte;
  241.     Mode :EntryModeType;
  242.     Term :Integer;
  243.     Done, Error :Boolean;
  244.     BATOverflow,
  245.     ASTOverflow :Boolean;
  246.     InputData   :Str80;
  247.     ErrorMsg    :Str80;
  248.     Arrows      :KeysAllowed;
  249.   begin
  250.     FillChar (StructureDataRecord, 512+35+1, 0);
  251.     With StructureDataRecord do With HOMBlock.HOM do
  252.     begin
  253.       { Set up constant and initial values. }
  254.       ID := 'HOM';
  255.       VolumeID := 'RAINBOW'#0;
  256.       SectorsPerTrack := 16;
  257.       SectorSize := 512;
  258.       AutoBoot := $FF;
  259.       { Now get the things the user is allowed to enter }
  260.       DrawOutline;
  261.       Center ('Please enter information about your disk below');
  262.       FVAttribute := AtUnderlineBold;
  263.       WriteFastLn ('IDENTIFICATION');
  264.       FVAttribute := AtNormal;
  265.       WriteFastLn ('Description (for future retrieval):');
  266.       WriteFastLn ('Type code for HOM block:             0');
  267.       WriteLn;
  268.       FVAttribute := AtUnderlineBold;
  269.       WriteFast   ('GEOMETRY');
  270.       FVAttribute := AtBold;
  271.       WriteFastLn (' (assumed: 512 bytes/sector, 16 sectors/track)');
  272.       FVAttribute := AtNormal;
  273.       WriteFastLn ('Number of Cylinders:                 100');
  274.       WriteFastLn ('Number of Surfaces (Heads):          4');
  275.       WriteLn;
  276.       FVAttribute := AtUnderlineBold;
  277.       WriteFastLn ('PHYSICAL CHARACTERISTICS');
  278.       FVAttribute := AtNormal;
  279.       WriteFastLn ('Write Precompensation first cyl/4:   1');
  280.       WriteFastLn ('Step Rate (.5ms units, 0 is 35╡s):   6');
  281.       WriteLn;
  282.       FVAttribute := AtUnderlineBold;
  283.       WriteFastLn ('OTHER OPTIONS');
  284.       FVAttribute := AtNormal;
  285.       WriteFastLn ('Tracks to reserve for alt. sectors:  1');
  286.       WriteLn;
  287.       Center
  288.      ('Enter requested info, pressing RETURN or up or down arrows after each');
  289.       Center ('Pressing just RETURN or arrows at any item leaves value as is');
  290.       Center ('Pressing MAIN SCREEN at any time aborts and goes to main menu');
  291.       Center ('Refer to WUTIL documentation for further information');
  292.       Mode := Succ(FirstEntryMode);
  293.       Done := False;  Error := False;
  294.       Name := '';  TypeCode := 0;  Cylinders := 100;  Surfaces := 4;
  295.       PreCompValue := 1;  StepRate := 6;  NumAltTracks := 1;
  296.       While not Done do
  297.       begin
  298.         If Pred(Mode) = FirstEntryMode then
  299.           Arrows := [DownArrowKeyVal, MainScreenKeyVal]
  300.         else
  301.           Arrows := [UpArrowKeyVal, DownArrowKeyVal, MainScreenKeyVal];
  302.         FVColumn := 40;
  303.         case Mode of
  304.         Description: begin
  305.           FVRow := 5;
  306.           ReadScreen (FVColumn, FVRow, 35, [' '..'~'], Arrows, InputData, Term);
  307.           If Ord(InputData[0]) > 0 then
  308.             Name := InputData
  309.           else
  310.             WriteFast (Name);
  311.           If Length(Name) = 0 then
  312.           begin
  313.             Error := True;
  314.             ErrorMsg := 'Name must not be blank';
  315.           end
  316.           else For I := 0 to NumDiskTypes - 1 do if Name = DiskTypeNames[I] then
  317.           begin
  318.             Error := True;
  319.             ErrorMsg := 'This name is already in use; please choose another';
  320.           end;
  321.          end;
  322.         TCode: begin
  323.           FVRow := 6;
  324.           ReadScreen (FVColumn, FVRow, 3, ['0'..'9'], Arrows, InputData, Term);
  325.           If Ord(InputData[0]) > 0 then
  326.           begin
  327.             Val (InputData, I, J);
  328.             If I > 255 then
  329.             begin
  330.               Error := True;
  331.               ErrorMsg := 'Type Code must be between 0 and 255';
  332.             end
  333.             else TypeCode := I;
  334.           end
  335.           else
  336.           begin
  337.             Str (TypeCode, InputData);
  338.             WriteFast (InputData);
  339.           end;
  340.          end;
  341.         NumCyl: begin
  342.           FVRow := 9;
  343.           ReadScreen (FVColumn, FVRow, 4, ['0'..'9'], Arrows, InputData, Term);
  344.           If Ord(InputData[0]) > 0 then
  345.           begin
  346.             Val (InputData, I, J);
  347.             If I = 0 then
  348.             begin
  349.               Error := True;
  350.               ErrorMsg := 'Number of cylinders cannot be zero!';
  351.             end
  352.             else if I > 1024 then
  353.             begin
  354.               Error := True;
  355.               ErrorMsg := 'Number of cylinders cannot be > 1024!';
  356.             end
  357.             else if I * Surfaces > (TrackLimit+1) then
  358.             begin
  359.               Error := True;
  360.               Str (TrackLimit+1, ErrorMsg);
  361.               ErrorMsg :=
  362.                Concat ('Number of tracks (cylinders x surfaces) must be <= ',
  363.                        ErrorMsg);
  364.             end
  365.             else Cylinders := I;
  366.           end
  367.           else
  368.           begin
  369.             Str (Cylinders, InputData);
  370.             WriteFast (InputData);
  371.           end;
  372.          end;
  373.         NumSurf: begin
  374.           FVRow := 10;
  375.           ReadScreen (FVColumn, FVRow, 2, ['0'..'9'], Arrows, InputData, Term);
  376.           If Ord(InputData[0]) > 0 then
  377.           begin
  378.             Val (InputData, I, J);
  379.             If I = 0 then
  380.             begin
  381.               Error := True;
  382.               ErrorMsg := 'Number of surfaces cannot be zero!';
  383.             end
  384.             else if I > 8 then
  385.             begin
  386.               Error := True;
  387.               ErrorMsg := 'Number of surfaces cannot be > 8!';
  388.             end
  389.             else if I * Cylinders > (TrackLimit+1) then
  390.             begin
  391.               Error := True;
  392.               Str (TrackLimit+1, ErrorMsg);
  393.               ErrorMsg :=
  394.                Concat ('Number of tracks (cylinders x surfaces) must be <= ',
  395.                        ErrorMsg);
  396.             end
  397.             else Surfaces := I;
  398.           end
  399.           else
  400.           begin
  401.             Str (Surfaces, InputData);
  402.             WriteFast (InputData);
  403.           end;
  404.          end;
  405.         Precomp: begin
  406.           FVRow := 13;
  407.           ReadScreen (FVColumn, FVRow, 4, ['0'..'9'], Arrows, InputData, Term);
  408.           If Ord(InputData[0]) > 0 then
  409.           begin
  410.             Val (InputData, I, J);
  411.             If I = 0 then
  412.             begin
  413.               Error := True;
  414.               ErrorMsg := 'Write Precompensation Cylinder should not be zero!';
  415.             end
  416.             else PreCompValue := I;
  417.           end
  418.           else
  419.           begin
  420.             Str (PreCompValue, InputData);
  421.             WriteFast (InputData);
  422.           end;
  423.          end;
  424.         StRate: begin
  425.           FVRow := 14;
  426.           ReadScreen (FVColumn, FVRow, 2, ['0'..'9'], Arrows, InputData, Term);
  427.           If Ord(InputData[0]) > 0 then
  428.           begin
  429.             Val (InputData, I, J);
  430.             If I > 15 then
  431.             begin
  432.               Error := True;
  433.               ErrorMsg := 'Step rate must be 15 (7.5ms) or less';
  434.             end
  435.             else StepRate := I;
  436.           end
  437.           else
  438.           begin
  439.             Str (StepRate, InputData);
  440.             WriteFast (InputData);
  441.           end;
  442.          end;
  443.         AltTracks: begin
  444.           FVRow := 17;
  445.           ReadScreen (FVColumn, FVRow, 2, ['0'..'9'], Arrows, InputData, Term);
  446.           If Ord(InputData[0]) > 0 then
  447.           begin
  448.             Val (InputData, I, J);
  449.             If (I = 0) or (I > 50) then
  450.             begin
  451.               Error := True;
  452.               ErrorMsg := 'Must have between 1 and 50 alternate sector tracks';
  453.             end
  454.             else NumAltTracks := I;
  455.           end
  456.           else
  457.           begin
  458.             Str (NumAltTracks, InputData);
  459.             WriteFast (InputData);
  460.           end;
  461.          end;
  462.         end;
  463.         If Term = MainScreenKeyCode then
  464.         begin
  465.           GetDiskData := False;
  466.           Exit;
  467.         end;
  468.         FVRow := 23;  FVColumn := 3;
  469.         If Error then
  470.         begin
  471.           FVAttribute := AtBlink;
  472.           Write (^G);
  473.           WriteFast (ErrorMsg);
  474.           Error := False;
  475.         end
  476.         else
  477.         begin
  478.           FVAttribute := AtNormal;
  479.           WriteFast
  480.            ('                                                            ');
  481.           If Term = UpArrowKeyCode then
  482.             Mode := Pred(Mode)
  483.           else
  484.           begin
  485.             Mode := Succ(Mode);
  486.             If Mode = LastEntryMode then Done := True;
  487.           end;
  488.         end;
  489.       end;
  490.       { We get here after all the information about the disk and its geometry
  491.         have been entered.  Now that we know this stuff, we can try to compute
  492.         other values to store on the HOM block.  First, set up the
  493.         manufacturing and maintenance cylinders as the last and second to last
  494.         cylinders on the disk, respectively. }
  495.       MfgCylinder := Cylinders - 1;
  496.       MaintCylinder := Cylinders - 2;
  497.       { Now we have to figure out where to put the various control blocks on
  498.         the disk.  We'll try to come close to what DEC does here for smaller
  499.         drives (this should work for 5, 10, and 20MB winnies).  That means
  500.         minimally that we will always put the DPD block in track 0, sector 3,
  501.         and the OSN block in track 0, sector 4 (DEC sometimes puts it in 4
  502.         and sometimes in 5, but we'll always use 4 and avoid wasting a sector;
  503.         that SHOULDN'T confuse any code which expects things to be in certain
  504.         places because such code couldn't be making assumptions about the OSN
  505.         block, and no one reads it anyway).  We'll try to locate the BAT and AST
  506.         blocks at the end of sector 0 after the OSN block, and the secondary
  507.         boot code at the beginning of track 1.  We also initially assume that
  508.         the alternate sector area starts at track 4.  These last three things
  509.         (BAT and AST locations, secondary boot location, and placement of
  510.         first alternate track) could end up being changed if things don't fit
  511.         nicely, which will be the case for drives much bigger than 20MB. }
  512.       With BOOTLocation DO
  513.       begin
  514.         Track := $01;  Sector := $01;  Length := $0C;
  515.       end;
  516.       With DPDLocation DO
  517.       begin
  518.         Track := $00;  Sector := $03;  Length := $01;
  519.       end;
  520.       With OSNLocation DO
  521.       begin
  522.         Track := $00;  Sector := $04;  Length := $01;
  523.       end;
  524.       With BATLocation DO
  525.       begin
  526.         Track := $00;  Sector := $05;
  527.         Length := ComputeBATBlocks (Cylinders*Surfaces);
  528.         BATOverflow := (Sector + Length > 17);
  529.       end;
  530.       With ASTLocation DO
  531.       begin
  532.         Track := $00;  Sector := BATLocation.Sector + BATLocation.Length;
  533.         Length := ComputeASTBlocks (NumAltTracks * 16);
  534.         ASTOverflow := (Sector + Length > 17);
  535.       end;
  536.       FirstAltTrack := 4;
  537.       { Now see if the AST area fits in track 0.  The variable ASTOverflow was
  538.         set up by the AST placement code to tell us this. }
  539.       If ASTOverflow then
  540.       begin
  541.         { The AST area did not fit.  Try moving the AST area to the end of
  542.           track 1, as far to the end as it will go. }
  543.         With ASTLocation do
  544.         begin
  545.           Track := $01;  Sector := 17-Length;
  546.         end;
  547.         { The AST area cannot overlay the secondary boot code.  If it does,
  548.           we'll have to move the boot code somewhere (to track 4, in our
  549.           case).  We know, by the way, that the AST area cannot be more than
  550.           16 sectors, because we limit the configuration to 50 alternate
  551.           sector tracks (more than anyone will ever need, anyway) and we only
  552.           need 8 AST blocks to track the resulting maximum of 800 alternate
  553.           sectors.
  554.           ** NOTE ** THIS CODE IS ASSUMING THAT THE BOOT AREA IS STILL LOCATED
  555.           AT TRACK 1, SECTOR 1 WHERE WE INITIALLY PLACED IT.  DON'T PUT ANY
  556.           CODE BEFORE HERE WHICH MOVES IT, PLEASE! }
  557.         If ASTLocation.Sector <= BOOTLocation.Length then with BOOTLocation do
  558.         begin
  559.           BOOTLocation.Track := FirstAltTrack;
  560.           FirstAltTrack := FirstAltTrack + 1;
  561.         end;
  562.         { Now, let's see how we are doing regarding the BAT area.  We have
  563.           moved the AST area out of its way at the end of track 0, but it's
  564.           still possible that the BAT area didn't fit there, even by itself.
  565.           We have a flag that tells us this, and if it says this problem
  566.           exists, we have to do something with the BAT area. }
  567.         If BATOverflow then
  568.         begin
  569.           { The BAT doesn't fit either (sigh).  Try and find a home for it.
  570.             If it is 16 sectors or smaller, then we will move it to track
  571.             1 and kick out the secondary boot code, if we haven't already
  572.             done that.  Then we'll move the AST area back into track 0.  We
  573.             know it will fit there because there are 12 sectors of space
  574.             after the OSN block in track 0 and the AST can't be more than 8. }
  575.           If BATLocation.Length < 17 then
  576.           begin
  577.             If BOOTLocation.Track = $01 then
  578.             begin
  579.               BOOTLocation.Track := FirstAltTrack;
  580.               FirstAltTrack := FirstAltTrack + 1;
  581.             end;
  582.             With BATLocation do
  583.             begin
  584.               Track := $01;  Sector := $01;
  585.             end;
  586.             ASTLocation.Track := $00; { Leave sector and length as is }
  587.             BATOverflow := False;
  588.           end;
  589.           If BATOverflow then
  590.           begin
  591.             { We continue here if the BAT is bigger than 16 sectors.  If
  592.               this is the case, then we can't make the BAT contiguous, like
  593.               we wanted to.  Instead, we'll (are you ready for this?) move
  594.               the AST area back into track 0, move the secondary boot code
  595.               back into track 1 (if it isn't there now), and put the BAT
  596.               starting at track 4.  Then we'll let the BAT go for as long as
  597.               it has to, crossing track boundaries, until it is done.  Ugh. }
  598.             ASTLocation.Track := $00; { Leave sector as is, should fit fine }
  599.             If BOOTLocation.Track <> $01 then
  600.             begin
  601.               FirstAltTrack := BOOTLocation.Track;
  602.               BOOTLocation.Track := $01;
  603.             end;
  604.             With BATLocation do
  605.             begin
  606.               Track := FirstAltTrack;
  607.               Sector := $01;
  608.               { Determine first free sector after BAT }
  609.               Trk := Track;  Sec := Sector;
  610.               For I := 1 to Length do NextSector (Trk, Sec);
  611.               If Sec = 1 then FirstAltTrack := Trk
  612.                          else FirstAltTrack := Trk + 1;
  613.             end;
  614.           end;
  615.         end;
  616.       end;
  617.       { That's it.  We have placed all the stuff on the disk in places where
  618.         it will fit.  We think. }
  619.     end;
  620.     { We've built ourselves an appropriate HOM block for the specified disk
  621.       geometry.  Now put a checksum in it. }
  622.     StructureDataRecord.HOMBlock.HOM.Checksum :=
  623.                                        -Checksum(StructureDataRecord.HOMBlock);
  624.     { Now we've formatted a new record for the file.  This is the one we
  625.       are going to use; it's also going to be added now to the file for
  626.       future reference. }
  627.     Seek (StructureDataFile, FileSize(StructureDataFile));
  628.     Write (StructureDataFile, StructureDataRecord);
  629.     GetDiskData := True;
  630.   end {GetDiskData};
  631.  
  632.   {sub}Procedure WriteBootCode;
  633.   begin
  634.     { Primary boot file first.  This should be just one block. }
  635.     FillChar (TempBlock, 512, 0);
  636.     BlockRead (PriBootFile, TempBlock, 4); { 4 128-byte records = 512 bytes }
  637.     WriteNoError (0, 1, TempBlock);
  638.     WriteNoError (2, 1, TempBlock); { Remember duplicate at track 2 }
  639.  
  640.     { Now secondary boot file.  There will be a few blocks here. }
  641.     Trk := HOMBlock.HOM.BOOTLocation.Track;
  642.     Sec := HOMBlock.HOM.BOOTLocation.Sector;
  643.     J := HOMBlock.HOM.BOOTLocation.Length;
  644.     For I := 0 to J-1 do
  645.     begin
  646.       FillChar (TempBlock, 512, 0);
  647.       If not EOF (SecBootFile) then BlockRead (SecBootFile, TempBlock, 4);
  648.       WriteNoError (Trk, Sec, TempBlock);
  649.       If Trk <= 1 then WriteNoError (Trk+2, Sec, TempBlock);
  650.       NextSector (Trk, Sec);
  651.     end;
  652.  
  653.   end {WriteBootCode};
  654.  
  655. begin
  656.   { Find and open the boot loader files we will need for this function. }
  657.  
  658.   PriBootFileSpec := PriBootFileName;
  659.   SecBootFileSpec := SecBootFileName;
  660.   StructureDataFileSpec := StructureDataFileName;
  661.  
  662.   FindOnPATH (PriBootFileSpec);
  663.   If Length(PriBootFileSpec) = 0 then
  664.   begin
  665.     CantFind (PriBootFileName);
  666.     Exit;
  667.   end;
  668.   Assign (PriBootFile, PriBootFileSpec);
  669.   Reset (PriBootFile);
  670.  
  671.   FindOnPATH (SecBootFileSpec);
  672.   If Length(SecBootFileSpec) = 0 then
  673.   begin
  674.     CantFind (SecBootFileName);
  675.     Close (PriBootFile);
  676.     Exit;
  677.   end;
  678.   Assign (SecBootFile, SecBootFileSpec);
  679.   Reset (SecBootFile);
  680.  
  681.   { If we were called just to copy boot loaders to disk, do that and exit.
  682.     Only continue if we actually are going to initialize a disk. }
  683.   If MainMenuFunc = MMCopyBoot then
  684.   begin
  685.     { Read the major structures from the disk.  They must be there in order
  686.       for us to proceed (the disk must have been initialized). }
  687.     If Not ReadMajorBlocks then Exit;
  688.     { All looks good.  Now say what we're doing and go to it. }
  689.     DrawOutline;
  690.     FVRow := 12;
  691.     Center ('Copying boot loaders PREBOOT.LDX and SECBOOT.LDX to the hard disk');
  692.     Center ('Please wait...');
  693.     WriteBootCode;
  694.     Close (PriBootFile);
  695.     Close (SecBootFile);
  696.     { We've finished.  Say so, wait for acknowledgement, and get out. }
  697.     FVRow := 20;  FVAttribute := AtBold;
  698.     Center ('Boot loaders have been written to disk -- press any key to go on');
  699.     I := RawChar;
  700.     Exit;
  701.   end;
  702.  
  703.   { We'll continue here only if we were called in order to actually initialize
  704.     a disk.  We'll get the file containing information about our disk types
  705.     and read it and then continue from there. }
  706.   FindOnPATH (StructureDataFileSpec);
  707.   If Length(StructureDataFileSpec) = 0 then
  708.   begin
  709.     CantFind (StructureDataFileName);
  710.     Close (SecBootFile);
  711.     Close (PriBootFile);
  712.     Exit;
  713.   end;
  714.   Assign (StructureDataFile, StructureDataFileSpec);
  715.   Reset (StructureDataFile);
  716.  
  717.   { Read the disk structure data file to get the names of each of the entries
  718.     stored there.  A maximum of 26 is permitted.  Any more will be ignored. }
  719.   NumDiskTypes := Min (FileSize (StructureDataFile), 26);
  720.   For I := 0 to NumDiskTypes - 1 do
  721.   begin
  722.     Seek (StructureDataFile, I);
  723.     Read (StructureDataFile, StructureDataRecord);
  724.     DiskTypeNames[I] := StructureDataRecord.Name;
  725.   end;
  726.  
  727.   { Display the formatting menu and decide how we will do this formatting }
  728.   FormattingMode := GetMenuSelection 
  729.                     (FormatMenu,
  730.                      [MainScreenKeyVal],
  731.                      'Please select the type of formatting you want.',
  732.                      'Selections nearer the top are slower but more reliable.',
  733.                      '', I);
  734.   If I = MainScreenKeyCode then
  735.   begin
  736.     Close (StructureDataFile);
  737.     Close (PriBootFile);
  738.     Close (SecBootFile);
  739.     Exit;
  740.   end;
  741.  
  742.   { Draw the disk selection screen and wait for a selection }
  743.   DrawOutline;
  744.   Center ('-- DISK TYPE MENU --');
  745.   For I := 0 to NumDiskTypes - 1 do
  746.   begin
  747.     FVColumn := ((I div 13)*39) + 3;
  748.     FVRow    :=  (I mod 13)     + 5;
  749.     FVAttribute := AtBold;
  750.     WriteFast (Char(Ord('A')+I));
  751.     FVAttribute := AtNormal;
  752.     WriteFast (Concat ('  ', DiskTypeNames[I]));
  753.   end;
  754.   FVRow := 19;
  755.   FVAttribute := AtBold;
  756.   Center
  757.     ('Press the letter corresponding to the type of disk you are initializing');
  758.   Center
  759.     ('If your disk type is not shown above, press ADDTNL OPTIONS');
  760.   Center
  761.     ('Or press MAIN SCREEN to abort and return to the main menu');
  762.  
  763.   Repeat
  764.     { Get a key.  If not a function key, eliminate shift/ctrl bits. }
  765.     I := (RawChar and CapsLockMask);
  766.     If (I and $100) = 0 then I := (I and not (Shift or Ctrl));
  767.     { Turn lower case to upper case }
  768.     If Char(I) in ['a'..'z'] then I := I - $20;
  769.     J := I - Ord('A');
  770.     If I = MainScreenKeyCode then
  771.     begin
  772.       Close (StructureDataFile);
  773.       Close (PriBootFile);
  774.       Close (SecBootFile);
  775.       Exit;
  776.     end
  777.     else if (I <> AddtnlOptionsKeyCode) and ((J < 0) or (J >= NumDiskTypes))
  778.       then Write (^G);
  779.   Until (I = AddtnlOptionsKeyCode) or ((J >= 0) and (J < NumDiskTypes));
  780.  
  781.   { If the user pressed the additional options key, then we must collect our
  782.     own information about the disk's geometry.  Otherwise, get the information
  783.     from the record in the file which was selected. }
  784.   If I = AddtnlOptionsKeyCode then 
  785.   begin
  786.     { Display screen to get disk geometry info and get it.  Exit if MAIN SCREEN
  787.       was pressed during this operation. }
  788.     If not GetDiskData then
  789.     begin
  790.       Close (StructureDataFile);
  791.       Close (PriBootFile);
  792.       Close (SecBootFile);
  793.       Exit;
  794.     end;
  795.   end
  796.   else
  797.   begin
  798.     Seek (StructureDataFile, J);
  799.     Read (StructureDataFile, StructureDataRecord);
  800.   end;
  801.  
  802.   { We can close the structure data file now.  We're done with it. }
  803.   Close (StructureDataFile);
  804.  
  805.   { We are now ready to start the formatting and initialization process.  But
  806.     before we do, we'd better make sure this is REALLY what we want. }
  807.   HOMBlock := StructureDataRecord.HOMBlock;
  808.  
  809.   DrawOutline;
  810.   FVAttribute := AtBold;
  811.   WriteFastLn ('These parameters will be used to format your disk:');
  812.   FVAttribute := AtNormal;
  813.   WriteFastLn (Concat ('Description: ',
  814.                        StructureDataRecord.Name));
  815.   PrintGeneralDiskInfo;
  816.   WriteLn;
  817.   FVAttribute := AtBold;
  818.   WriteFastLn ('Press any key to continue...');
  819.   I := RawChar;
  820.   If I = MainScreenKeyCode then
  821.   begin
  822.     Close (PriBootFile);
  823.     Close (SecBootFile);
  824.     Exit;
  825.   end;
  826.  
  827.   DrawOutline;
  828.   FVAttribute := AtBold;
  829.   Center (Concat ('About to format and initialize disk as ',
  830.                   StructureDataRecord.Name));
  831.   DrawBox (4, 5, 77, 11, AtBlinkBold);
  832.   FVRow := 5; FVAttribute := AtDefault;
  833.   Write (^G^G);
  834.   Center (' WARNING ');
  835.   FVAttribute := AtBold;
  836.   Center ('You are about to format and initialize your hard disk.');
  837.   Center ('This action will result in the LOSS of ALL data currently on');
  838.   Center ('the disk.  You should not attempt this operation unless you do');
  839.   Center ('not want any of your hard disk data or you have backed up');
  840.   Center ('whatever you wish to save.');
  841.   FVRow := 14;
  842.   Center ('Press RESUME to continue');
  843.   Center ('or Press MAIN SCREEN to cancel formatting/initializing');
  844.   Repeat
  845.     I := (RawChar and CapsLockMask);
  846.     If I = MainScreenKeyCode then
  847.     begin
  848.       Close (PriBootFile);
  849.       Close (SecBootFile);
  850.       Exit;
  851.     end
  852.     else if I <> ResumeKeyCode then Write (^G);
  853.   Until I = ResumeKeyCode;
  854.  
  855.   DrawBox (4, 14, 77, 18, AtBlinkBold);
  856.   FVRow := 14; FVAttribute := AtDefault;
  857.   Write (^G^G);
  858.   Center (' SECOND WARNING ');
  859.   FVAttribute := AtBold;
  860.   Center ('If you press RESUME now, you will start formatting and initializing.');
  861.   Center ('There will be no turning back.');
  862.   Center ('Have you backed up everything you intend to save?');
  863.   FVRow := 21;  FVAttribute := AtBold;
  864.   Center ('Press RESUME to begin formatting');
  865.   Center ('or Press MAIN SCREEN to cancel and return to main menu');
  866.   Repeat
  867.     I := (RawChar and CapsLockMask);
  868.     If I = MainScreenKeyCode then
  869.     begin
  870.       Close (PriBootFile);
  871.       Close (SecBootFile);
  872.       Exit;
  873.     end
  874.     else if I <> ResumeKeyCode then Write (^G);
  875.   Until I = ResumeKeyCode;
  876.  
  877.   { We have been authorized to start formatting.  First of all, let's make
  878.     sure we can't exit from here on. }
  879.   EXITAllowed := False;
  880.  
  881.   { Now set up some initial things. }
  882.   FillChar (SectorTable, 2*(TrackLimit+1), 0);{ Initially, all sectors good }
  883.   FillChar (ASTVector, 3*800, 0);             { No alternate sectors initially }
  884.  
  885.   With HOMBlock.HOM do
  886.   begin
  887.     { Initialize the controller, since we can't be sure this was done properly
  888.       before.  Also fill in the appropriate fields in the BIOS. }
  889.     HDMAXTRK[CurrentDrive]^  := (Cylinders * Surfaces) - 1;
  890.     HDSTEPR[CurrentDrive]^   := StepRate;
  891.     HDPRECOMP[CurrentDrive]^ := PreCompValue;
  892.     { Initialize controller, then wait a bit for it to settle }
  893.     Port[Command2Port] := 2;
  894.     J := 1; For I := 1 to 500 do j := j + 1;
  895.     { Set precomp and SDH registers }
  896.     Port[PrecompPort] := PreCompValue;
  897.     Port[SDHPort] := $20; { 512 byte sectors, head 0, drive 0 }
  898.     { Set task file registers for track 0, sector 1 }
  899.     Port[CylinderLowPort] := 0;
  900.     Port[CylinderHighPort] := 0;
  901.     Port[SectorNumberPort] := 1;
  902.     Port[SectorCountPort] := 1;
  903.     { Issue "restore" command with correct step rate, then wait for it
  904.       to finish }
  905.     ISRFlag[CurrentDrive]^ := 0;
  906.     Port[CommandPort] := (StepRate and $0F) + $10;
  907.     If not HDDone then
  908.     begin
  909.       DrawOutline;
  910.       Write (^G);
  911.       FVRow := 10;  FVAttribute := AtBold;
  912.       Center ('FATAL ERROR -- UNABLE TO RESET HARD DISK');
  913.       WriteLn;
  914.       Center ('Something appears to be wrong with your hard disk hardware');
  915.       Center ('It cannot be formatted and initialized');
  916.       WriteLn;
  917.       Center ('Press any key to continue');
  918.       I := RawChar;
  919.       Close (PriBootFile);
  920.       Close (SecBootFile);
  921.       Exit;
  922.     end;
  923.   end;
  924.  
  925.   { Now it's time to actually format the disk.  We'll do calls to the
  926.     BIOS formatting routines to do this.  We'll start at the last track
  927.     number (after subtracting enough tracks for one cylinder) and format
  928.     each track in turn, working toward track 0.  After each track is
  929.     formatted, we may also attempt to do a write (with verify) of up to two
  930.     different types of data for each sector (depending on the formatting mode
  931.     selected).  We'll mark bad sectors wherever this fails.  We'll also mark
  932.     all sixteen sectors in a track as bad if the format fails.  Note that we
  933.     skip the last cylinder in formatting because, for most manufacturers of
  934.     hard disks, there is special data there which describes manufacturing
  935.     defects.  We don't want to write over it or change its format (it is
  936.     written using 256-byte sectors). }
  937.  
  938.   DrawOutline;
  939.   FVAttribute := AtNormal;
  940.   If FormattingMode <> FMInitializeOnly then
  941.   begin
  942.     J := 0; { Accumulated bad sector count }
  943.     FillChar (ZeroesData, 512, 0);
  944.     FillChar (OnesData, 512, $5A); { 0 1 0 1 1 0 1 0 }
  945.     For Trk := (HDMAXTRK[CurrentDrive]^ - HOMBlock.HOM.Surfaces) downto 0 do
  946.     begin
  947.       FVRow := 12;
  948.       Str (Trk:4, TrackDisplay);
  949.       Center (Concat ('Now formatting track: ', TrackDisplay));
  950.       If not FormatTrack (Trk) then
  951.       begin
  952.         SectorTable[Trk].Num := $FFFF;
  953.         J := J + 16;
  954.       end
  955.       else if FormattingMode <> FMNoVerify then For Sec := 1 to 16 do
  956.       begin
  957.         If FormattingMode = FMDoubleVerify then
  958.         begin
  959.           If (not WriteSector (Trk, Sec, OnesData)) or
  960.              (not WriteSector (Trk, Sec, ZeroesData)) then
  961.           begin
  962.             MarkSectorBad (Trk, Sec);
  963.             J := J + 1;
  964.           end;
  965.         end
  966.         else
  967.         begin
  968.           If (not WriteSector (Trk, Sec, ZeroesData)) then
  969.           begin
  970.             MarkSectorBad (Trk, Sec);
  971.             J := J + 1;
  972.           end;
  973.         end;
  974.       end {For each sector If not no verify mode};
  975.       If J > 0 then { If bad sectors, display count so far }
  976.       begin
  977.         Str (J, TrackDisplay);
  978.         Center (Concat ('Bad sectors detected: ', TrackDisplay));
  979.       end {If bad sectors};
  980.     end {For each track};
  981.   end {If not just initializing};
  982.  
  983.   { We have completed formatting.  Now it's time to initialize the disk with
  984.     the data we've set up.  First, write the HOM block. }
  985.   FVRow := 12;
  986.   Center ('Formatting completed; Now initializing disk...');
  987.   WriteMajorBlock (0, 2, HOMBlock);
  988.   { Write the AST and BAT blocks, because we have routines which do that.
  989.     Note that the AST blocks will always indicate no alternate sectors
  990.     assigned, even if there are bad sectors.  This is because the assignment
  991.     of alternate sectors is done in the partitioning phase for CP/M and CCP/M
  992.     partitions. }
  993.   WriteBATBlocks;
  994.   WriteASTBlocks;
  995.   { Build and write a DPD block.  The block will show no partitions built. }
  996.   FillChar (TempBlock, 512, 0);
  997.   With TempBlock.DPD do
  998.   begin
  999.     ID := 'DPD';
  1000.     MaxEntries := 15;
  1001.   end;
  1002.   With HOMBlock.HOM.DPDLocation do WriteMajorBlock (Track, Sector, TempBlock);
  1003.   { Build and write an OSN block.  This block will show the standard operating
  1004.     systems in positions 1, 2, and 3.  Postition zero and all after 3 will be
  1005.     nulls. }
  1006.   FillChar (TempBlock, 512, 0);
  1007.   With TempBlock.OSN do
  1008.   begin
  1009.     ID := 'OSN';
  1010.     MaxEntries := 31;
  1011.     Entry[1] := 'CP/M-86/80      ';
  1012.     Entry[2] := 'MS-DOS          ';
  1013.     Entry[3] := 'CCP/M-86        ';
  1014.   end;
  1015.   With HOMBlock.HOM.OSNLocation do WriteMajorBlock (Track, Sector, TempBlock);
  1016.  
  1017.   { We've written almost everything.  The remainder of what we will write comes
  1018.     from the boot files (.LDX) we have.  Note that there is a potential
  1019.     problem here: these files could have been found on the hard disk!  If this
  1020.     is the case, this will probably not work, but this serves the person right,
  1021.     I suppose. }
  1022.   WriteBootCode;
  1023.   Close (PriBootFile);
  1024.   Close (SecBootFile);
  1025.  
  1026.   { We've finished the formatting and initializing process.  Now tell the
  1027.     guy we're done, and we can return. }
  1028.   DrawOutline;
  1029.   FVRow := 8;  FVAttribute := AtBold;
  1030.   Center ('Your disk has been formatted and initialized.');
  1031.   FVAttribute := AtNormal;
  1032.   WriteLn;
  1033.   Center ('However, your hard disk does not yet have any partitions');
  1034.   Center ('defined.  You should now proceed to the "repartition disk"');
  1035.   Center ('function to install partitions on your disk and make it usable.');
  1036.   FVRow := 20;  FVAttribute := AtBold;
  1037.   Center ('Press any key to continue');
  1038.   I := RawChar;
  1039. end {FormatAndInitialize};
  1040.  
  1041. { SetAutoBoot - Sets/changes auto boot partition. }
  1042. overlay procedure SetAutoBoot;
  1043. var
  1044.   Current :Integer;
  1045.   Pointer :Integer;
  1046.   I, J    :Integer;
  1047. begin
  1048.   If Not ReadMajorBlocks then Exit;
  1049.   DrawOutline;
  1050.   FVAttribute := AtBold;
  1051.   FVRow := 2;
  1052.   Center ('Boot Partition Selection');
  1053.   FVRow := 23;
  1054.   Center
  1055.    ('Use arrows to select, then press DO to set; press MAIN SCREEN when done');
  1056.   StartFastVideo (15, 4, AtDefault, 79, 23);
  1057.   WriteFastLn ('Partition  Drive  Operating System');
  1058.   WriteLn;
  1059.   WriteFastLn (' (no auto boot)');
  1060.   Current := 0;
  1061.   With DPDBlock.DPD do For I := 1 to EntryCount do With Entry[I] do
  1062.   begin
  1063.     WriteFastLn (Concat (Name, '     ',
  1064.                          Chr (Ord('A')+LogicalUnit-1), ':   ',
  1065.                          OSNBlock.OSN.Entry[OSNIndex]));
  1066.     If HOMBlock.HOM.BootTrack = FirstTrack then Current := I;
  1067.   end;
  1068.   Pointer := Current;
  1069.  
  1070.   while True do { Repeat until main screen key or exit key }
  1071.   begin
  1072.     StartFastVideo (9, 6, AtBold, 79, 24);
  1073.     For I := 0 to DPDBlock.DPD.EntryCount do
  1074.     begin
  1075.       If I = Pointer then
  1076.       begin
  1077.         If I = Current then WriteFastLn ('--> *')
  1078.                        else WriteFastLn ('-->  ');
  1079.       end
  1080.       else
  1081.       begin
  1082.         If I = Current then WriteFastLn ('    *')
  1083.                        else WriteFastLn ('     ');
  1084.       end;
  1085.     end;
  1086.     J := (RawChar and CapsLockMask);
  1087.     If (J = UpArrowKeyCode) and (Pointer > 0) then
  1088.       Pointer := Pointer - 1
  1089.     else if (J = DownArrowKeyCode) and (Pointer < DPDBlock.DPD.EntryCount) then
  1090.       Pointer := Pointer + 1
  1091.     else if (J = DoKeyCode) then
  1092.     begin
  1093.       Current := Pointer;
  1094.       If Current = 0 then
  1095.       begin
  1096.         HOMBlock.HOM.BootTrack := 0;
  1097.         HOMBlock.HOM.AutoBoot := $FF;
  1098.       end
  1099.       else
  1100.       begin
  1101.         HOMBlock.HOM.BootTrack := DPDBlock.DPD.Entry[Current].FirstTrack;
  1102.         HOMBlock.HOM.AutoBoot := DPDBlock.DPD.Entry[Current].LogicalUnit;
  1103.       end;
  1104.       WriteMajorBlock (0, 2, HOMBlock);
  1105.     end
  1106.     else if (J = MainScreenKeyCode) then Exit
  1107.     else Write (^G);
  1108.   end;
  1109. end {SetAutoBoot};
  1110.  
  1111. { DumpSector - Dumps the contents of a sector to the screen. }
  1112. overlay procedure DumpSector;
  1113. var
  1114.   Track         :Integer;
  1115.   MaxTracks     :Integer;
  1116.   Sector        :Byte;
  1117.   StartLine     :Integer;
  1118.   I, J          :Integer;
  1119.   K             :Byte;
  1120.   HaveSector    :Boolean;
  1121.   DisplayNeeded :Boolean;
  1122.   XlateMode     :Boolean;
  1123.   DisplayAttribute :Integer; { Attribute used to display dump data }
  1124.   TSRadix       :Integer; { Radix in which track & sector are displayed 10/16 }
  1125.   LineOfDump    :Array [0..31] OF Str80;
  1126. begin
  1127.   { Try to read the HOM block from the disk in order to determine the number
  1128.     of surfaces the disk has.  If we fail, we'll still try to process things
  1129.     and continue to assume 4 surfaces on the disk, but we'll warn that this
  1130.     may be problematical. }
  1131.   HOMBlock.HOM.Surfaces := 4;
  1132.   If not ReadHOMBlock (0, 2, HOMBlock) then
  1133.   begin
  1134.     DrawOutline;
  1135.     FVRow := 7;
  1136.     FVAttribute := AtBold;
  1137.     Write (^G);
  1138.     Center ('Your disk is not initialized!');
  1139.     FVAttribute := AtNormal;
  1140.     WriteLn;
  1141.     Center ('Your disk does not appear to be properly initialized.');
  1142.     Center ('WUTIL is unable to read the disk''s HOM block in order to');
  1143.     Center ('determine information about the disk''s geometry.');
  1144.     Center ('Specifically, WUTIL cannot determine how many surfaces (heads)');
  1145.     Center ('your disk has.  This information is required in order to map');
  1146.     Center ('track numbers into their Cylinder/Surface equivalents.');
  1147.     Center ('WUTIL will continue processing with the assumption that');
  1148.     Center ('your disk drive, like most Rainbow winchester disks, has four');
  1149.     Center ('surfaces.  If this is not the case, the data from this');
  1150.     Center ('dump facility will be unreliable.');
  1151.     WriteLn;
  1152.     FVAttribute := AtBold;
  1153.     Center ('Press any key to continue...');
  1154.     I := RawChar;
  1155.     { Since we couldn't read the HOM block, it is unlikely that MS-DOS could
  1156.       either.  The value of MAXTRK in the BIOS, therefore, is suspect: It may
  1157.       be too low.  We'll set it to an artificially high value in order to
  1158.       guarantee that we always TRY to read the track specified.  This is,
  1159.       perhaps, not ideal, but it is the best we can do under the
  1160.       circumstances. }
  1161.     HDMAXTRK[CurrentDrive]^ := 1023;
  1162.   end;
  1163.  
  1164.   { Now, various initializations. }
  1165.   HaveSector := FALSE;
  1166.   DisplayNeeded := TRUE;
  1167.   XlateMode := FALSE;
  1168.   Track := 0;
  1169.   MaxTracks := HOMBlock.HOM.Cylinders * HOMBlock.HOM.Surfaces - 1 - HOMBlock.HOM.Surfaces;
  1170.   Sector := 1;
  1171.   TSRadix := 16;
  1172.   DrawOutline;
  1173.   StartFastVideo (2, 6, AtDefault, 79, 23);
  1174.   DrawBox (11, 2, 20, 4, AtBold);  DrawBox (61, 2, 70, 4, AtBold);
  1175.   FVAttribute := AtBold; FVRow := 4;
  1176.   FVColumn := 14; WriteFast ('Track');
  1177.   FVColumn := 63; WriteFast ('Sector');
  1178.   DrawBox (3, 6, 78, 23, AtBold);
  1179.   StartFastVideo (6, 7, AtDefault, 77, 22);
  1180.   FVRow := 6; FVColumn := 6;
  1181.   WriteFastLn
  1182.    ('xF xE xD xC xB xA x9 x8|x7 x6 x5 x4 x3 x2 x1 x0  offs  0123456789ABCDEF');
  1183.   { Note: The loop which follows displays stuff and handles function keys.
  1184.     The display area is exactly 16 lines long, and the routines here will
  1185.     be entered with the current position at the upper left of the display
  1186.     area.  Routines which display things should always display exactly 16
  1187.     lines, so that previous data will be overwritten. }
  1188.   while TRUE do { loop forever (until EXIT or MAIN SCREEN key) }
  1189.   begin
  1190.     { First update track and sector fields }
  1191.     FVAttribute := AtBold; FVRow := 3;
  1192.     FVColumn := 14;
  1193.     if TSRadix = 16 then WriteFast (Hex4Digit (Track))
  1194.                     else Write (Track:4);
  1195.     FVColumn := 63;
  1196.     if not XlateMode then
  1197.     begin
  1198.       WriteFast ('  ');
  1199.       if TSRadix = 16 then WriteFast (Hex2Digit (Sector))
  1200.                       else Write (Sector:2);
  1201.       WriteFast (' ');
  1202.     end
  1203.     else
  1204.     begin
  1205.       if TSRadix = 16 then WriteFast (Hex2Digit (Sector))
  1206.                       else Write (Sector:2);
  1207.       WriteFast ('=');
  1208.       if TSRadix = 16 then WriteFast (Hex2Digit (Xlate(Sector)))
  1209.                       else Write (Xlate(Sector):2);
  1210.     end;
  1211.     FVColumn := FVLMargin; FVRow := FVTMargin; FVAttribute := AtDefault;
  1212.     if DisplayNeeded then
  1213.     begin
  1214.       { We'll either display the help screen or the data depending on whether
  1215.         we "have a sector" or not. }
  1216.       if HaveSector then
  1217.       begin
  1218.         FVRow := 3; FVAttribute := AtBold;
  1219.         Center ('Press HELP key for help');
  1220.         FVRow := FVTMargin; FVAttribute := DisplayAttribute;
  1221.         for I := StartLine to StartLine + 15 do WriteFastLn (LineOfDump[I]);
  1222.       end
  1223.       else {if not HaveSector then}
  1224.       begin
  1225.         FVRow := 3;
  1226.         Center ('                       ');
  1227.         FVRow := FVTMargin; FVAttribute := AtNormal;
  1228.         WriteFastLn
  1229.     ('General instructions for sector dump facility:                          ');
  1230.         WriteFastLn
  1231.     ('* LEFT and RIGHT ARROWs decrease or increase sector number by 1''s      ');
  1232.         WriteFastLn
  1233.     ('* SHIFT LEFT/RIGHT ARROWs decrease/increase track number by 1''s        ');
  1234.         WriteFastLn
  1235.     ('* CTRL LEFT/RIGHT ARROWs decrease/increase track number by 10''s        ');
  1236.         WriteFastLn
  1237.     ('* CTRL SHIFT LEFT/RIGHT ARROWs decrease/increase track numbers by 100''s');
  1238.         WriteFastLn
  1239.     ('* After selecting track and sector, pressing DO reads & displays, e.g.:');
  1240.         FVAttribute := AtReverseBold;
  1241.         WriteFastLn
  1242.     ('20 20 20 20 20 47 46 45|20 20 20 20 44 43 42 41  0000  ABCD    EFG     ');
  1243.         FVAttribute := AtNormal;
  1244.         WriteFastLn
  1245.     ('  <---------- data in hexadecimal -------------  addr  ----in ASCII--->');
  1246.         WriteFastLn
  1247.     ('  Display lines are read from the address out; text is read normally;  ');
  1248.         WriteFastLn
  1249.     ('  Hex is read RIGHT TO LEFT (This may appear odd, but it makes for more');
  1250.         WriteFastLn
  1251.     ('  "natural" reading of multi-byte numeric values -- high order first!).');
  1252.         WriteFastLn
  1253.     ('* UP and DOWN ARROWs and NEXT SCREEN and PREV SCREEN scroll display    ');
  1254.         WriteFastLn
  1255.     ('* SELECT key toggles radix of track & sector (but dump is always hex)  ');
  1256.         WriteFastLn
  1257.     ('* The ADDTNL OPTIONS key toggles sector xlate mode (for partition data)');
  1258.         WriteFastLn
  1259.     ('* The HELP key redisplays this text                                    ');
  1260.         WriteFastLn
  1261.     ('* The MAIN SCREEN key returns to the WUTIL main menu, EXIT goes to DOS ');
  1262.       end;
  1263.       DisplayNeeded := FALSE;
  1264.     end;
  1265.     I := (RawChar and CapsLockMask);
  1266.     if I = DoKeyCode then
  1267.     begin
  1268.       FVAttribute := AtReverse;
  1269.       for j := 1 to 7 do WriteFastLn
  1270.     ('                                                                       ');
  1271.       WriteFastLn
  1272.     ('                        Reading; please wait...                        ');
  1273.       for j := 1 to 8 do WriteFastLn
  1274.     ('                                                                       ');
  1275.       if XlateMode then K := Xlate(Sector) else K := Sector;
  1276.       if ReadSector (Track, K, TempBlock) then
  1277.       begin
  1278.         HaveSector := True;
  1279.         DisplayNeeded := True;
  1280.         DisplayAttribute := AtReverseBold;
  1281.         StartLine := 0;
  1282.         for I := 0 to 31 do
  1283.         begin
  1284.           LineOfDump[I] := '';
  1285.           for J := ((I*16)+15) downto (I*16) do
  1286.           begin
  1287.             LineOfDump[I] := Concat (LineOfDump[I],
  1288.                                      Hex2Digit (TempBlock.SectorBytes[J]), ' ');
  1289.           end;
  1290.           LineOfDump[I] := Concat (LineOfDump[I], ' ', Hex4Digit(I*16), '  ');
  1291.           for J := (I*16) to ((I*16)+15) do
  1292.           begin
  1293.             LineOfDump[I] := Concat (LineOfDump[I],
  1294.                                      PrintChar(TempBlock.SectorBytes[J]));
  1295.           end;
  1296.           Delete (LineOfDump[I], 24, 1);
  1297.           Insert ('|', LineOfDump[I], 24);
  1298.         end;
  1299.       end
  1300.       else { Read failed }
  1301.       begin
  1302.         HaveSector := False;
  1303.         DisplayNeeded := False;
  1304.         Write (^G);
  1305.         for j := 1 to 7 do WriteFastLn
  1306.     ('                                                                       ');
  1307.         WriteFastLn
  1308.     ('                -- UNABLE TO READ REQUESTED SECTOR --                  ');
  1309.         for j := 1 to 8 do WriteFastLn
  1310.     ('                                                                       ');
  1311.       end;
  1312.     end
  1313.     else if (I = SelectKeyCode) then TSRadix := 26 - TSRadix
  1314.     else if (I = UpArrowKeyCode) and (HaveSector) and (StartLine > 0) then
  1315.     begin
  1316.       StartLine := StartLine - 1;
  1317.       DisplayNeeded := True;
  1318.     end
  1319.     else if (I = DownArrowKeyCode) and (HaveSector) and (StartLine < 16) then
  1320.     begin
  1321.       StartLine := StartLine + 1;
  1322.       DisplayNeeded := True;
  1323.     end
  1324.     else if (I = PrevScreenKeyCode) and (HaveSector) and (StartLine > 0) then
  1325.     begin
  1326.       StartLine := 0;
  1327.       DisplayNeeded := True;
  1328.     end
  1329.     else if (I = NextScreenKeyCode) and (HaveSector) and (StartLine < 16) then
  1330.     begin
  1331.       StartLine := 16;
  1332.       DisplayNeeded := True;
  1333.     end
  1334.     else if (I = AddtnlOptionsKeyCode) then
  1335.     begin
  1336.       XlateMode := (not XlateMode);
  1337.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1338.       begin
  1339.         DisplayNeeded := True;
  1340.         DisplayAttribute := AtReverse;
  1341.       end;
  1342.     end
  1343.     else if (I = LeftArrowKeyCode) and ((Sector > 1) or (Track > 0)) then
  1344.     begin
  1345.       PrevSector (Track, Sector);
  1346.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1347.       begin
  1348.         DisplayNeeded := True;
  1349.         DisplayAttribute := AtReverse;
  1350.       end;
  1351.     end
  1352.     else if (I = RightArrowKeyCode) and ((Sector < 16) or (Track < MaxTracks)) then
  1353.     begin
  1354.       NextSector (Track, Sector);
  1355.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1356.       begin
  1357.         DisplayNeeded := True;
  1358.         DisplayAttribute := AtReverse;
  1359.       end;
  1360.     end
  1361.     else if (I = Shift+LeftArrowKeyCode) and (Track > 0) then
  1362.     begin
  1363.       Track := Track - 1;
  1364.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1365.       begin
  1366.         DisplayNeeded := True;
  1367.         DisplayAttribute := AtReverse;
  1368.       end;
  1369.     end
  1370.     else if (I = Shift+RightArrowKeyCode) and (Track < MaxTracks) then
  1371.     begin
  1372.       Track := Track + 1;
  1373.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1374.       begin
  1375.         DisplayNeeded := True;
  1376.         DisplayAttribute := AtReverse;
  1377.       end;
  1378.     end
  1379.     else if (I = Ctrl+LeftArrowKeyCode) and (Track > 0) then
  1380.     begin
  1381.       Track := Track - TSRadix;
  1382.       if Track < 0 then Track := 0;
  1383.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1384.       begin
  1385.         DisplayNeeded := True;
  1386.         DisplayAttribute := AtReverse;
  1387.       end;
  1388.     end
  1389.     else if (I = Ctrl+RightArrowKeyCode) and (Track < MaxTracks) then
  1390.     begin
  1391.       Track := Track + TSRadix;
  1392.       if Track > MaxTracks then Track := MaxTracks;
  1393.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1394.       begin
  1395.         DisplayNeeded := True;
  1396.         DisplayAttribute := AtReverse;
  1397.       end;
  1398.     end
  1399.     else if (I = Ctrl+Shift+LeftArrowKeyCode) and (Track > 0) then
  1400.     begin
  1401.       Track := Track - TSRadix*TSRadix;
  1402.       if Track < 0 then Track := 0;
  1403.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1404.       begin
  1405.         DisplayNeeded := True;
  1406.         DisplayAttribute := AtReverse;
  1407.       end;
  1408.     end
  1409.     else if (I = Ctrl+Shift+RightArrowKeyCode) and (Track < MaxTracks) then
  1410.     begin
  1411.       Track := Track + TSRadix*TSRadix;
  1412.       if Track > MaxTracks then Track := MaxTracks;
  1413.       if (HaveSector) and (DisplayAttribute = AtReverseBold) then
  1414.       begin
  1415.         DisplayNeeded := True;
  1416.         DisplayAttribute := AtReverse;
  1417.       end;
  1418.     end
  1419.     else if I = HelpKeyCode then
  1420.     begin
  1421.       HaveSector := False;
  1422.       DisplayNeeded := True;
  1423.     end
  1424.     else if I = MainScreenKeyCode then Exit
  1425.     else Write (^G);
  1426.   end;
  1427.  
  1428. end {DumpSector};
  1429.  
  1430. overlay procedure ParkHeadsForShipping;
  1431. var
  1432.   I :Integer;
  1433.   CylNum :String [10];
  1434. begin
  1435.   If not ReadMajorBlocks then Exit;
  1436.   DrawOutline;
  1437.   With HOMBlock.HOM do
  1438.   begin
  1439.     Str (Cylinders, CylNum);
  1440.     ManualSeek (Cylinders, StepRate);
  1441.   end;
  1442.   FVRow := 5; FVAttribute := AtBold;
  1443.   Center (Concat ('The controller has been commanded to seek to cylinder ',
  1444.                   CylNum));
  1445.   FVAttribute := AtNormal;
  1446.   Center ('This cylinder is one cylinder beyond the last valid data cylinder');
  1447.   WriteLn;
  1448.   Center ('On most hard disk drives, this will park the read/write heads');
  1449.   Center ('in a "shipping zone" to protect damage to the disk surface or');
  1450.   Center ('to your data during transportation.');
  1451.   WriteLn;
  1452.   Center ('Your drive may not work this way.  You should always be very');
  1453.   Center ('careful to pack your drive well prior to moving or shipping it.');
  1454.   WriteLn;
  1455.   FVAttribute := AtBold;
  1456.   Center ('To preserve the protection afforded by this function,');
  1457.   Center ('TURN OFF YOUR SYSTEM NOW!');
  1458.   FVAttribute := AtNormal;
  1459.   WriteLn;
  1460.   Center
  1461.   ('Further accesses to the disk will move the heads out of the shipping zone');
  1462.   Center ('(Press any key if you wish to continue anyway)');
  1463.   I := RawChar;
  1464. end {ParkHeadsForShipping};
  1465.