home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dskutl / partitn.arc / PARTITN.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-10-20  |  18.7 KB  |  623 lines

  1. {$R-}
  2. program partitn;
  3. uses dos, crt, sounds;
  4.  
  5. const ESC = #$1b;
  6.       EndChars : set of char = ['Q','q','x','X', ESC];
  7. type
  8.     FileNameStr  = String[64];
  9.  
  10.     DiskAddress = record
  11.         Head     : byte;
  12.         Sector   : byte;
  13.         Track    : byte;
  14.         end;
  15.  
  16.     PartitionRecord  = record
  17.         IsStartUp   : byte;     { 0x80: is startup,  00: is not }
  18.         StartDA     : DiskAddress;
  19.         SystemId    : byte;     {  1: first MS_DOS (12 bit FAT)
  20.                    2: root Xenix
  21.                    3: user Xenix
  22.                    4: first MS_DOS (16 bit FAT)
  23.                                   63: Interactive Unix
  24.                   F2: Second MS_DOS (either FAT)
  25.                   FF: bad track info of Xenix     }
  26.     EndDA       : DiskAddress;
  27.     StartLogicalSector : LongInt;
  28.     NumLogicalSectors  : LongInt;
  29.     end;
  30.  
  31.     PartitionTable = record
  32.     BootCode  : array[1..$1be] of byte;
  33.         Partitions: array[1..4] of PartitionRecord;
  34.         Marker    : word;
  35.         end;
  36.  
  37.     Bigbuf = array[0..511] of byte;
  38.  
  39. Var
  40.     PTfile    : file of Bigbuf;
  41.     PTfilename: FileNameStr;
  42.     chh       : char;
  43.     DeviceNum : byte;         {info for current disk device}
  44.     DeviceChar: char;
  45.     PTtemp    : PartitionTable;
  46.     PTtempx   : Bigbuf Absolute PTtemp;
  47.     PT        : PartitionTable;
  48.     PTx       : Bigbuf absolute PT;
  49.     PTsource  : FileNameStr;  {where we got current PT record from}
  50.     PTdevice  : char;         {if from a drive, the letter}
  51.     I,J       : Word;
  52.     regs      : Registers;
  53.     PTDA      : DiskAddress; {raw boot record disk address}
  54.     UserDA    : DiskAddress; {when user enters a disk address}
  55.     PThasPartitions : Boolean;      {type of recd in PT}
  56.     PThasSomething  : Boolean;
  57.     SaveMainY : Byte;
  58.  
  59.  
  60. Procedure DisplayHelp;
  61. var ch:char;
  62. begin
  63. clrscr;
  64. writeln('This program lets you read and write disk and partition boot records.');
  65. writeln('It lets you move these records into a file and lets you put whatever');
  66. writeln('you want into a boot record.  You can change a partition type and can');
  67. writeln('merge the code from one boot record with the partition table of another.');
  68. writeln;
  69. writeln('The program NEVER writes anything out until you enter a Write command.');
  70. writeln('All changes are done to an in memory buffer.  This buffer gets written');
  71. writeln('by the write command.  The write command asks for verification before');
  72. writeln('overwriting a boot record on the hard disk.  BUT BE CAREFUL !!!');
  73. writeln;
  74. writeln('For all commands, <esc>, Q, or X mean the same thing: quit to the next level');
  75. writeln;
  76. writeln('The first record on a disk is a boot record.  It gets read in at the start');
  77. writeln('of the boot sequence.  The code in it can do whatever it wants.  By');
  78. writeln('convention a HARD disk boot record has a partition table in it.  A');
  79. writeln('partition is a hunk of disk; on the front of a BOOTABLE partition is');
  80. writeln('another boot record.  The disk boot record reads in and transfers control');
  81. writeln('to the partition boot record.  A floppy disk boot record is essentially');
  82. writeln('a partition boot record to boot off drive A:');
  83. writeln;
  84. writeln('If you have a disk with two bootable systems (Unix and MS-DOS), you can');
  85. writeln('copy the respective partition boot records to the boot record on a');
  86. writeln('diskette.  Then this diskette will directly boot that partition.');
  87. writeln;
  88. write('continue . . .');
  89. beep;  ch:=ReadKey;  clrscr;
  90. end {DisplayHelp};
  91.  
  92. Procedure MainWindow;
  93. begin  Window(1,1,40,25); GotoXY(1,SaveMainY); end;
  94.  
  95. Procedure PartitionWindow;
  96. begin SaveMainY:=WhereY; Window(41,1,80,25); end;
  97.  
  98. Procedure PrintDiskAddress (Var DA:DiskAddress);
  99. Var ccc : word;
  100. Begin with DA do begin
  101.     ccc := ((Sector and $c0) shl 2) + Track;
  102.     write (ccc, '/', Head, '/', Sector and $3F);
  103. end end {PrintDiskAddress};
  104.  
  105.  
  106. function NullDA(DA:DiskAddress):boolean;
  107.     begin  NullDA := (DA.head=0) and (DA.track=0) and (DA.sector=0);  end;
  108.  
  109.  
  110. Procedure PrintPartition (Var pp:PartitionRecord; num:byte);
  111. var UnKnown:boolean;
  112. begin with pp do begin
  113.         write(' ', num);
  114.     if IsStartup = $80 then write(' A')
  115.                            else write('  ');
  116.  
  117.         UnKnown:=False;
  118.     write(' type : ');
  119.     case SystemId of
  120.           1:  write ('MS-DOS1 (12 fat)');
  121.           2:  write ('XENIX root');
  122.               3:  write ('XENIX user');
  123.           4:  write ('MS-DOS1 (16 fat)');
  124.             $63:  write ('Interactive Unix');
  125.         $F2:  write ('MS-DOS2');
  126.         $FF:  write ('XENIX bad track ');
  127.        else   begin
  128.                   UnKnown := True;
  129.                   write ('unknown (', SystemId, ')');
  130.                   end;
  131.         end {case};
  132.         writeln;
  133.         if (not NullDA(StartDA)) or (not NullDA(EndDA)) then
  134.             begin
  135.             write('     c/h/r: ');     PrintDiskAddress(StartDA);
  136.         write(' to ');  PrintDiskAddress(EndDA);
  137.             writeln;
  138.             end;
  139.  
  140.         if (not UnKnown) or
  141.            (StartLogicalSector<>0) or (NumLogicalSectors<>0) then
  142.               writeln ('     1st/#: ', StartLogicalSector,
  143.                        '/', NumLogicalSectors, ' sectors');
  144.  
  145.         writeln;
  146. end end {PrintPartition};
  147.  
  148.  
  149. Function CheckRecordMarker(var PT:PartitionTable):boolean;
  150. begin
  151.         CheckRecordMarker:=true;
  152.         if PT.Marker<>$AA55 then
  153.            begin
  154.            CheckRecordMarker:=false;
  155.            Writeln('NOT A VALID BOOT RECORD !!!');  blat;
  156.            end;
  157. end {CheckRecordMarker};
  158.  
  159.  
  160. Function CheckPartitionTable(var PT:PartitionTable):boolean;
  161. var i,cnt:byte;
  162. begin with PT do begin
  163.       CheckPartitionTable:=true;
  164.       cnt:=0;
  165.       for i:=1 to 4 do
  166.           if Partitions[i].IsStartUp=$80 then cnt:=cnt+1
  167.           else if Partitions[i].IsStartUp<>0 then cnt:=cnt+10;
  168.       if cnt<>1 then
  169.           begin
  170.           CheckPartitionTable:=false;
  171.           Writeln('THIS IS A VALID BOOT RECORD');
  172.           Writeln('( DOES NOT HAVE A PARTITION TABLE )');
  173.           blat;
  174.           end;
  175. end end {CheckPartitionTable};
  176.  
  177.  
  178. Procedure PrintPartitionRecord(var PT:PartitionTable);
  179. begin with PT do begin
  180.         PartitionWindow;
  181.         clrscr;
  182.         writeln(PTsource);
  183.         PThasPartitions:=false;
  184.         if PThasSomething then
  185.            if CheckRecordMarker(PT) then
  186.               if CheckPartitionTable(PT) then
  187.                   begin
  188.                   PThasPartitions:=true;
  189.                   for i:=4 downto 1 do
  190.                           PrintPartition(PT.Partitions[i], 5-i);
  191.                   end;
  192.         MainWindow;
  193. end end {PrintPartitionRecord};
  194.  
  195.  
  196. Procedure ClearDiskette(Device:byte);
  197. {if device is diskette, read change status so IO will not fail if changed}
  198. begin
  199.      if Device < $80 then
  200.         With Regs do begin
  201.              AH := $00;
  202.              DL := Device;
  203.              Intr($13, Regs);
  204.              writeln('** ', AH);
  205.              end;
  206. end {ClearDiskette};
  207.  
  208. Procedure WriteDisk (Var DA:DiskAddress; Device:byte; var buffer:BigBuf);
  209. var XX : byte;
  210. begin with Regs, DA do begin
  211.       XX := 0;
  212.       DH := Head;
  213.       DL := Device;
  214.       CH := Track;
  215.       CL := Sector;
  216.       BX := Ofs(buffer);
  217.       ES := Seg(buffer);
  218.       Repeat
  219.             XX := XX+1;
  220.             AH := 3;          {write}
  221.             AL := 1;          {1 sector}
  222.             Intr($13, Regs);
  223.             Until (Device>=$80) or (XX>1) or (AH<>6);
  224.       if AH<>0 then
  225.           begin  WriteLn('DISK WRITE ERROR ', AH, ' !!!');  blat;  end
  226.        else
  227.           WriteLn('Record Successfully Written');
  228. end end {WriteDisk};
  229.  
  230.  
  231. Function ReadDisk (Var DA:DiskAddress; Device:byte; var buffer:BigBuf):boolean;
  232. var XX : Byte;
  233. begin with Regs, DA do begin
  234.       XX := 0;
  235.       DH := Head;
  236.       DL := Device;
  237.       CH := Track;
  238.       CL := Sector;
  239.       BX := Ofs(buffer);
  240.       ES := Seg(buffer);
  241.       Repeat
  242.             XX := XX+1;
  243.             AH := 2;     {read}
  244.             AL := 1;     {1 sector}
  245.             Intr($13, Regs);
  246.             Until (Device>=$80) or (XX>1) or (AH<>6);
  247.       ReadDisk := true;
  248.       if AH<>0 then
  249.           begin
  250.           writeln('DISK READ ERROR ', AH, ' !!!');
  251.           blat;  ReadDisk:=False;
  252.           end
  253.        else
  254.           WriteLn('Record Successfully Read In.');
  255. end end {ReadDisk};
  256.  
  257. function TestForEndChars(ch:char):boolean;
  258. begin
  259.      if ch<>ESC then write(ch);
  260.      writeln;
  261.      TestForEndChars := ch in EndChars;
  262. end;
  263.  
  264.  
  265. Function SaveToFile:boolean;
  266. label QUIT;
  267. var TempName : fileNameStr;
  268.      ch : char;
  269. begin
  270.      PTfileName := 'BOOT' + PTdevice + '.RCD';
  271.      Write('File to Save to (', PTfileName, ') : ');
  272.      beep;  ReadLn(TempName);
  273.      if (length(TempName)=1) and (UpCase(TempName[1])='Q') then goto QUIT;
  274.      if TempName <>'' then  PTfileName := TempName;
  275.      Assign(PTfile, PTfileName);
  276.      ch:='Y';
  277.      {$I-} Reset(PTfile); {$I+}
  278.      if IOresult=0 then
  279.         begin
  280.         writeln('FILE ', PTfileName, ' EXISTS!');
  281.         write  ('     OVERWRITE (Y/N) ? ');
  282.         beep;  ch := UpCase(ReadKey); Writeln(ch);
  283.         close(PTfile);
  284.         end;
  285.  
  286.      if ch='Y' then
  287.         begin
  288.         ReWrite(PTfile);
  289.         Write(PTfile, PTx);
  290.                 Close(PTfile);
  291.         SaveToFile:=True;
  292.         Writeln('Successful Write');
  293.         end
  294.      else
  295. QUIT:   begin  SavetoFile:=False;  end;
  296.      WriteLn;
  297.      end {SavetoFile};
  298.  
  299.  
  300. Function GetFromFile:boolean;
  301. var TempName : FileNameStr;
  302. begin
  303.      PTfileName := 'BOOT' + DeviceChar + '.RCD';
  304.      Write('File to read from (', PTfileName, ') : ');
  305.      beep;  Readln(TempName);
  306.      if TempName<>'' then PTfileName:=TempName;
  307.      Assign(PTfile, PTfileName);
  308.      {$I-} reset(PTfile); {$I+}
  309.      if IOresult<>0 then
  310.         begin
  311.         Writeln('OPEN FAILURE FILE ', PTfilename, ', NOTHING READ !!!');
  312.         blat;
  313.         GetFromFile:=false;
  314.         end
  315.      else
  316.         begin
  317.         Read(PTfile, PTx);
  318.         Close(PTfile);
  319.         WriteLn('Successful file read');
  320.         GetFromFile := True;
  321.         end;
  322.      writeln;
  323. end {GetFromFile};
  324.  
  325. Function GetPartitionDA (var Ption:PartitionRecord; var DA:DiskAddress)
  326.                 : boolean;
  327. begin
  328. GetPartitionDA:=false;
  329. if (not NullDA(Ption.StartDA)) and
  330.    (not NullDA(Ption.EndDA)) then
  331.        begin  DA:=Ption.StartDA;  GetPartitionDA:=true;  end;
  332. end {GetPArtitionDA};
  333.  
  334.  
  335. Function GetCRH(var DA:DiskAddress):boolean;
  336. {ask user for a disk address cc/hh/rr}
  337. label BAD;
  338. var sc,sh,sr:string[4];
  339.     temp    :string[24];
  340.     i,track :word;
  341. begin
  342. GetCRH:=false;
  343. write('Enter cc/hh/rr : ');
  344. readln(temp);
  345. i:=pos('/',temp);
  346. if i=0 then goto BAD;
  347. sc:=copy(temp,1,i-1);  temp:=copy(temp,i+1,255);
  348. i:=pos('/',temp);
  349. if i=0 then goto BAD;
  350. sh:=copy(temp,1,i-1);  sr:=copy(temp,i+1,255);
  351. val(sc, track, i);
  352. if i<>0 then goto BAD;
  353. val(sh, DA.head, i);
  354. if i<>0 then goto BAD;
  355. val(sr, DA.sector, i);
  356. if i<>0 then goto BAD;
  357. DA.sector := DA.sector or ((track and $ff00) shr 2);
  358. DA.track  := track and $00ff;
  359. GetCRH:=True;
  360. if i<>0 then
  361. BAD: writeln('INVALID CC/HH/RR');
  362. end {GetCRH};
  363.  
  364.  
  365. Procedure ReadWhat;
  366. {Read selected, ask what to read}
  367. var ch, chp : char;
  368.     st,sh,ss: string[4];
  369. begin
  370.      Writeln('1  - Read disk ', DeviceChar, ' boot record');
  371.      Writeln('2  - Read record from MS-DOS file');
  372.      Writeln('3  - Read from disk address');
  373.      if PThasSOmething and PThasPartitions then
  374.         Writeln('Pn - Read partition n boot record');
  375.      Write  ('    : ');
  376.      repeat
  377.           beep; ch:=UpCase(ReadKey);
  378.           until (ch in ['1','2','3', 'P']) or (ch in EndChars);
  379.      chp:=ch;
  380.      if ch='P' then
  381.         begin
  382.         write(ch);
  383.         repeat
  384.            beep; chp:=UpCase(ReadKey);
  385.            until (chp in ['1' .. '4']) or (chp in EndChars);
  386.         end;
  387.  
  388.      if TestForEndChars(chp) then exit;
  389.  
  390.      if ch='1' then
  391.         begin
  392.         PThasSomething :=  ReadDisk(PTDA, DeviceNum, PTx);
  393.         PTdevice :=  DeviceChar;
  394.         PTSource := 'Device: ' + PTdevice;
  395.         end
  396.      else if ch='2' then
  397.         begin
  398.         if GetFromFile then
  399.            begin
  400.            PThasSomething:=true;
  401.            PTdevice := '?';
  402.            PTsource := PTfileName;
  403.            end;
  404.         end
  405.      else if ch='3' then
  406.         begin
  407.         if GetCRH(UserDA) then
  408.            begin
  409.            PThasSomething := ReadDisk(UserDA, DeviceNum, PTx);
  410.            PTdevice := DeviceChar;
  411.            Str(UserDA.track + ((UserDA.Sector and $c0) shl 2) , st);
  412.            Str(UserDA.head,  sh);
  413.            Str(UserDA.Sector and $3f,ss);
  414.  
  415.            PTsource := PTdevice + ':' + st + '/' + sh + '/' + ss;
  416.            end;
  417.         end
  418.      else if (ch='P') and PThasSomething and PThasPartitions then
  419.         begin
  420.         if GetPartitionDA(PT.Partitions[5-Ord(chp)+Ord('0')], UserDA) then
  421.            begin
  422.            PThasSOmething := ReadDisk(UserDA, DeviceNum, PTx);
  423.            PTdevice := DeviceChar;
  424.            PTsource := 'Partition ' + chp;
  425.            end
  426.         else
  427.            begin  WriteLn('Invalid Partition');  blat;  exit;  end;
  428.         end;
  429.  
  430.      PrintPartitionRecord(PT);
  431. end {ReadWhat};
  432.  
  433.  
  434. Procedure WriteWhat;
  435. label FIN1;
  436. var ch,chh:char;
  437.     OK:boolean;
  438. begin
  439.      if not PThasSomething then
  440.         begin  Writeln('Nothing to write');  exit; end;
  441.  
  442.      Writeln('1 - Write disk ', DeviceChar, ' boot record');
  443.      Writeln('2 - Write record to MS-DOS file');
  444.      Writeln('3 - Write to disk address');
  445.      Write  ('    : ');
  446.      repeat
  447.           beep; ch:=UpCase(ReadKey);
  448.           until (ch in ['1','2','3']) or (ch in EndChars);
  449.      if TestForEndChars(ch) then goto FIN1;
  450.  
  451.      chh:='Y';
  452.      OK :=True;
  453.      if (ch='1') or (ch='3') then
  454.         begin
  455.         Writeln('Are you sure you want to overwrite');
  456.         Write  ('the boot record on drive ', DeviceChar, ' (Y/N) ? ');
  457.         beep;  chh:= UpCase(ReadKey);  Writeln(chh);
  458.         if chh<>'Y' then goto FIN1;
  459.  
  460.         if (ch='1') and (not PThasPartitions) and (DeviceChar>='C') then
  461.               begin
  462.               writeln('The record does not have a valid partition table');
  463.               write  ('Are you sure you want to do this (Y/N) ? ');
  464.               beep;  chh:=UpCase(ReadKey);  Writeln(chh);
  465.               if chh<>'Y' then goto FIN1;
  466.               end;
  467.  
  468.         writeln;
  469.         writeln('One last chance, this is DANGEROUS!');
  470.         write  ('    ARE YOU SURE (Y/N) ? ');
  471.         beep;  chh:=UpCase(ReadKey);  Writeln(chh);
  472.         if chh<>'Y' then goto FIN1;
  473.         end;
  474.  
  475.      if ch='1' then
  476.         WriteDisk(PTDA, DeviceNum, PTx);
  477.  
  478.      if ch='2' then
  479.         OK:=SaveToFile;
  480.  
  481.      if (not OK) then
  482. FIN1:   begin  writeln('NOTHING WRITTEN !!!');  blat;  end;
  483. end {WriteWhat};
  484.  
  485.  
  486. Function Merger : boolean;
  487. {this procedure merges the partition table and code portions of record
  488. in buffer and current record on disk}
  489. var ch:char;
  490. begin
  491.      Merger := false;
  492.      if PThasSomething and PThasPartitions and
  493.         ReadDisk(PTDA, DeviceNum, PTtempx) and
  494.         CheckRecordMarker(PTtemp)          and
  495.         CheckPartitionTable(PTtemp) then
  496.         begin
  497.         writeln('Merge:');
  498.         writeln('1 - code on disk, table in buffer');
  499.         write  ('2 - table on disk, code in buffer  : ');
  500.         repeat
  501.              beep; ch:=ReadKey
  502.              until (ch in ['1','2']) or (ch in EndChars);
  503.         if TestForEndChars(ch) then exit;
  504.  
  505.         if ch='1' then
  506.            PT.BootCode := PTtemp.BootCode;
  507.         if ch='2' then
  508.            PT.Partitions := PTtemp.PArtitions;
  509.  
  510.         PrintPartitionRecord(PT);
  511.         Merger := true;
  512.         end;
  513. end {Merger};
  514.  
  515.  
  516. function EditPartition : boolean;
  517. var ch, chh : char;
  518.     PartType: byte;
  519. begin
  520.    EditPartition := false;
  521.    if not (PThasSomething and PThasPartitions) then  exit;
  522.    write('ENTER PARTITION NUMBER : ');
  523.    repeat
  524.        beep;  ch := UpCase(ReadKey);
  525.        until (ch in ['1' .. '4']) or (ch in EndChars);
  526.    if TestForEndChars(ch) then exit;
  527.    writeln;
  528.    writeln('ENTER NEW PARTION SYSTEM ID');
  529.    writeln ('1 - MS-DOS1 (12 fat)');
  530.    writeln ('2 - XENIX root');
  531.    writeln ('3 - XENIX user');
  532.    writeln ('4 - MS-DOS1 (16 fat)');
  533.    writeln ('5 - Interactive Unix');      { $63}
  534.    writeln ('6 - MS-DOS2 (not boot)');    { $F2}
  535.    write   ('7 - XENIX bad track  : ');   { $FF}
  536.    repeat
  537.          beep;  chh := UpCase(ReadKey);
  538.          until (ch in ['1' .. '7']) or (ch in EndChars);
  539.    if TestForEndChars(chh) then exit;
  540.    PartType := Ord(chh) - Ord('0');
  541.    if chh='5' then PartType := $63;
  542.    if chh='6' then PartType := $F2;
  543.    if chh='7' then PartType := $FF;
  544.    PT.Partitions[5 - Ord(ch)+Ord('0')].SystemID := PartType;
  545.    PrintPartitionRecord(PT);
  546.    EditPartition := true;
  547. end {EditPartition};
  548.  
  549.  
  550. Function GetDiskName : Boolean;
  551. var ch : char;
  552. begin
  553.         GetDiskName:=False;
  554.         write('ENTER DISK TO WORK WITH (A ... D) : ');
  555.         repeat
  556.               beep; ch:=UpCase(ReadKey);
  557.               until (ch in ['A' .. 'D']) or (ch in EndChars);
  558.         if TestForEndChars(ch) then exit;
  559.         DeviceChar := ch;
  560.         if DeviceChar<'C'
  561.               then  DeviceNum := Ord(DeviceChar) - Ord('A')
  562.               else  DeviceNum := Ord(DeviceChar) - Ord('C') + $80;
  563.          GetDiskName:=true;
  564. end {GetDiskName};
  565.  
  566.  
  567. begin {main}
  568.         Clrscr;
  569.         repeat
  570.             Writeln('PARTITN 2.0 by Richard Marks.  (FREE WARE)');
  571.             Writeln;
  572.             Writeln('WARNING: IF YOU DO NOT KNOW WHAT YOU ARE DOING');
  573.             Writeln;
  574.             Writeln(' YOU CAN TRASH THE HARD DISK WITH THIS PROGRAM');
  575.             writeln;  write('PROCEED (Y/N/H) ? ');
  576.             beep;  chh:=UpCase(ReadKey);
  577.             if chh='H' then DisplayHelp;
  578.             until (chh<>'H');
  579.         if chh<>'Y' then Halt;
  580.         ClrScr;
  581.  
  582.         SaveMainY:=1; MainWindow;
  583.         Writeln;
  584.         PTDA.Track := 0;
  585.         PTDA.Head  := 0;
  586.         PTDA.Sector:= 1;
  587.  
  588.         PThasSomething :=False;
  589.         PThasPartitions:=False;
  590.         PTsource := ' ';
  591.         PTdevice := '?';
  592.  
  593.         if not GetDiskName then halt;
  594.  
  595.   while true do
  596.         begin
  597.         writeln;
  598.         writeln('N - work with new disk');
  599.         writeln('R - read record');
  600.         if PThasSomething then
  601.              writeln('W - write record');
  602.         if PThasSomething and PThasPartitions then
  603.             begin
  604.             writeln('M - merge portions of records');
  605.             writeln('E - edit partition info');
  606.             end;
  607.         ClrEol; write  ('    : ');
  608.         repeat
  609.               beep;  chh:=UpCase(ReadKey);
  610.               until (chh in ['E','N','R','W','M']) or (chh in EndChars);
  611.         if TestForEndChars(chh) then Halt;
  612.         writeln;
  613.  
  614.         case chh of
  615.         'N' : if GetDiskName then;
  616.         'R' : ReadWhat;
  617.         'W' : if PThasSomething then  WriteWhat;
  618.         'M' : if Merger then;
  619.         'E' : if EditPartition then;
  620.         end {case};
  621.      end {while};
  622. end.
  623.