home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dskutl / reform15.arc / REFORMAT.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1987-05-24  |  21.4 KB  |  542 lines

  1. (*
  2. To:  INFO-IBMPC-REQUEST@USC-ISIB.ARPA
  3. From:  U001222%HNYKUN11.BITNET@WISCVM.WISC.EDU
  4. Subject: reformat.pas
  5. *)
  6. PROGRAM reformat;
  7. {
  8.   Program to reformat any disk attached to an Olivetti PC or compatible.
  9.   The progam will work well on any MS/PC-DOS machine running under DOS
  10.   versions 2.00 up to and including 3.10. Fixed disks up to 32 Meg.
  11.  
  12.     V1.50 Extensions made for big FATs. WORD.INC included for handling of
  13.     word integers. MS-DOS function INT21 / 32H used for drive information.
  14.     Corrected the problem of DOS losing track of the current directory.
  15.  
  16.     The program has been tested under DOS 2.00 thru 3.10
  17.     It will probably work under DOS 3.20 too, but this version will not
  18.     run when you try to do so. If you want to test it with DOS 3.20, look
  19.     for the string DOS_Versions (it's somewhere near the end of the program)
  20.     in this program, and include that version number into the test.
  21.     Please let the author know whether you had success or not.
  22.  
  23.     Jos Wennmacker                                    July 86.
  24.     Universitair Rekencentrum
  25.     Geert Grooteplein Zuid 41
  26.     6525 GA Nijmegen
  27.     The Netherlands
  28.  
  29.     BITNET address: U015415 at HNYKUN22
  30.  
  31.     V1.5  Jos added new 16-bit and word code, handling up to 30Meg
  32.     hard disks, etc.  I cleaned up the integer math inline procedures
  33.     a little.
  34.     David Kirschbaum, Toad Hall
  35.  
  36.     V1.23 Added FRAMER.INC, WRITEF.INC for framing, fast screen write,
  37.     fast screen line clear.  Tightened up displays a little.
  38.     This version is now VERY PC-specific.  Generic MS-DOS functions
  39.     for screen stuff to follow.
  40.     David Kirschbaum, Toad Hall.
  41.  
  42.     V1.22 Added inline code to replace the INT25.ASM and INT26.ASM
  43.     files.
  44.     David Kirschbaum, Toad Hall, 3 May 86
  45.  
  46.     V1.21(mod) not publicly released. Changes made by Rick Watson to let
  47.     the program recognize the big (16 bit) FATs. He made it run on 20 Meggers
  48.     under DOS 3.x. Martin Hobson made it run on 30 Meggers under DOS 3.x.
  49.     May 86.
  50.  
  51.     V1.21 Small corrections made to avoid Turbo integer overflow. (Hey,
  52.     Borland, what about a WORD type in Turbo, would be very usefull using
  53.     the MSDOS features!).
  54.  
  55.     V1.20 First release to the public domain.
  56.     What started as a favour to a friend grew into a nice program.
  57.     Do you like it? Let me know about it! If I know many people to use it,
  58.     I'll keep it up to date, and send you new releases.
  59.     Jos Wennmacker
  60.  
  61. }
  62. {$C-}
  63. {-------------------------------- Global types -------------------------------}
  64.  
  65. TYPE
  66.  
  67. {------------------- types for word arithmetic  see REFORMAT.IN1 -------------}
  68.  
  69.   word                =      INTEGER;
  70.  
  71.   Relational_Operator =      (Eq, Gt, Lt, Ne, Ge, Le);
  72.  
  73. {------------------------ for interrupts and DOS calls -----------------------}
  74.  
  75.   Regpack             =
  76.     RECORD CASE INTEGER OF
  77.       1: (ax, bx, cx, dx, bp, si, di, ds, es, flags : word);
  78.       2: (al, ah, bl, bh, cl, ch, dl, dh            : Byte);
  79.     END;
  80.  
  81. {----------------------------- Bootrecord layout -----------------------------}
  82.  
  83.   Boot                =                { the layout of the DOS boot record    }
  84.     RECORD
  85.       Jump:                  ARRAY[0..2] OF Byte; { Near jump to boot code    }
  86.       OEM :                  ARRAY[0..7] OF CHAR; { eight character OEM name  }
  87.       sectorSize:            word;     { number of bytes in one sector        }
  88.       clusterSize:           Byte;     { sectors per cluster                  }
  89.       reservedSectors:       word;     { DOS boot code sector(s) typically 1  }
  90.       numberOfFATs:          Byte;     { usually 2, but often 1 for RAM disks }
  91.       rootDirSize,                     { maximum entries in root directory    }
  92.       totalSectors:          word;     { total sectors in the logical image   }
  93.       mediaDescriptor:       Byte;     { A limited description of the drive
  94.                                          bit 0 = 1: twosided, 0: not two-sided
  95.                                          bit 1 = 1: 8-sector, 0: not 8-sector
  96.                                          bit 2 = 1: removable 0: not removable
  97.                                          bits 3-7 must be set to 1            }
  98.       fatSize,                         { number of sectors in each FAT copy   }
  99.       trackSize,                       { number of sectors per track          }
  100.       numberOfHeads,                   { number of heads                      }
  101.       hiddenSectors:         word;     { sectors hidden from DOS, preceding
  102.                                          the DOS partition: including the
  103.                                          master boot record and any non-DOS
  104.                                          partitions                           }
  105.     END;
  106.  
  107. {---------------- Layout of DOS function 32h disk parameter block ------------}
  108.  
  109.   Parms_32            =     ^Parameter_table;
  110.  
  111.   Parameter_Table     =                { layout of the DOS function 32 table  }
  112.     RECORD
  113.       assignedDisk,                    { 0 = A, 1 = B, ...                    }
  114.       altAD:                 Byte;     { same as above, but 0 for RAM disk    }
  115.       sectorSize:            word;     { number of bytes in one sector        }
  116.       clusterSize_1,                   { sectors per cluster minus 1          }
  117.       numberOfHeads_1:       Byte;     { number of heads minus 1              }
  118.       reservedSectors:       word;     { DOS boot code sector(s) typically 1  }
  119.       numberOfFATs:          Byte;     { usually 2, but often 1 for RAM disks }
  120.       rootDirSize,                     { maximum entries in root directory    }
  121.       firstDataSector,                 { first sector for data storage        }
  122.       totalDataClusters_1:   word;     { total data clusters plus 1           }
  123.       fatSize:               Byte;     { number of sectors in each FAT copy   }
  124.       firstDirectorySector:  word;     { first sector of the root directory   }
  125.       DeviceDriverAddress:  ^byte;     { Far (offset, segment) address of the
  126.                                          DOS device driver for the drive      }
  127.       mediaDescriptor:       word;     { A limited description of the drive
  128.                                          only the low order byte is used:
  129.                                          bit 0 = 1: twosided, 0: not two-sided
  130.                                          bit 1 = 1: 8-sector, 0: not 8-sector
  131.                                          bit 2 = 1: removable 0: not removable
  132.                                          bits 3-7 must be set to 1            }
  133.       NextParameterTable:    Parms_32; { far pointer to next disk table       }
  134.       currentDirCluster:     word;     { Starting cluster of current working
  135.                                          directory. According to Glenn Roberts
  136.                                          in his May 86 PC Tech Journal article
  137.                                          "Finding Disk Parameters" this would
  138.                                          only hold for PC DOS 2.00
  139.                                                                               }
  140.       CurrentDirName:        ARRAY [0..63] OF CHAR
  141.                                        {
  142.                                          The name of the current working
  143.                                          directory. This does not hold for
  144.                                          DOS 3.x versions. Only for 2.00      }
  145.     END;
  146.  
  147. {-------- Long byte and integerarays for Disk Transfer Area, Fats etc. -------}
  148.  
  149.   intArray   = ARRAY[0..32766] OF INTEGER;
  150.  
  151.   buffer     = ARRAY[0..32766] OF Byte;
  152.  
  153. {--------------------- Element of tree of directory entries ------------------}
  154.  
  155.   DirectoryPointer = ^DirectoryEntry;
  156.  
  157.   longInteger      = ARRAY[0..1] OF INTEGER;
  158.  
  159.   DirectoryEntry =
  160.     RECORD
  161.       EntryName:          ARRAY[0..10] OF CHAR; { name + extension w/o period
  162.                                          If the first char is $00 then this
  163.                                          entry was never used. Also the next
  164.                                          entries in this directory have never
  165.                                          been used.
  166.                                          If the first char is $E5 then this
  167.                                          entry was erased.                    }
  168.       attribute:          Byte;        { attribute of entry:
  169.                                          bit      if set means
  170.                                           0       read only file
  171.                                           1       hidden file
  172.                                           2       system file
  173.                                           3       volume label
  174.                                           4       subdirectory
  175.                                           5       archive bit                 }
  176.       reserved:           ARRAY[1..10] OF Byte; { for future use              }
  177.       timeLastUpdated:    word;                 { mapped in the bits:
  178.                                          <     hh     > <    mm    > <   xx  >
  179.                                          15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  180.                                          where:
  181.                                          hh  binary number of hours [0..23]
  182.                                          mm  binary number of minutes [0..59]
  183.                                          xx  binary number of two-second
  184.                                              increments [0..28]               }
  185.       dateLastUpdated:    word;        { mapped in the bits
  186.                                          <        yy       > < mm  > <   dd  >
  187.                                          15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  188.                                          where:
  189.                                          yy  binary number of years [0..119]
  190.                                              (1980-2099)
  191.                                          mm  binary number of month [1..129]
  192.                                          dd  binary number of day [1..31]     }
  193.       startingCluster:    word;        { index of the file's first cluster    }
  194.       fileSize:           longInteger; { filesize in bytes                    }
  195.       newStartingCluster: word;
  196.       Next,
  197.       SubDirectory:       DirectoryPointer;
  198.     END;
  199.  
  200. {------------------------------- Helps for I/O -------------------------------}
  201.  
  202.   WorkString     = STRING[255];
  203.   Line           = STRING[78];
  204.   Str40          = STRING[40];
  205.  
  206.   Disk_Activity  = (reading,writing);
  207.  
  208. {-------------------------------- constants ----------------------------------}
  209.  
  210. CONST
  211.  
  212.   Header:          STRING[37] = ' REFORMAT: an original JOS disk tool ';
  213.   Version:         STRING[10] = 'Ver: 1.50 ';
  214.   PDS:             STRING[24] = ' Public Domain Software ';
  215.   EnterStr:        STRING[28] = 'Press Enter to return to DOS';
  216.   HiSpace:         STRING[01] = #160;  {WriteF blank line flag                }
  217.  
  218. {--------------------------- FAT special values ------------------------------}
  219.  
  220.   unused:          word       = $0000; { we use typed constants, because      }
  221.   reservedMinimum: word       = $0FF0; { we might have to change these values }
  222.   reservedMaximum: word       = $0FF6; { the values entered here are for      }
  223.   badCluster:      word       = $0FF7; { the old, small FAT format of 12 bits }
  224.   lastMinimum:     word       = $0FF8; { per entry. The new FAT format uses   }
  225.   lastMaximum:     word       = $0FFF; { 16 bit-entries. See the procedure    }
  226.   lastNormal:      word       = $0FFF; { Getinformation.                      }
  227.  
  228. {---------------------- file attribute byte values----------------------------}
  229.  
  230.   READONLY         = $01;              { file attribute byte                  }
  231.   HIDDENFILE       = $02;
  232.   SYSTEMFILE       = $04;
  233.   VOLUMELABEL      = $08;
  234.   SUBDIRECTORY     = $10;
  235.   ARCHIVE          = $20;
  236.  
  237.   NEVERUSED        = $00;              { first byte of file's name            }
  238.   ERASED           = $E5;
  239.  
  240.   FIXEDDISK        = $F8;              { some values of mediaDescriptor       }
  241.   DUAL8SECTOR      = $FF;
  242.   SINGLE8SECTOR    = $FE;
  243.   DUAL9SECTOR      = $FD;
  244.   SINGLE9SECTOR    = $FC;
  245.  
  246. {---------- constants for the screen layout, for FRAMER and WRITEF procedures }
  247.  
  248.   MIDDLEFIELDY     = 18;               { little window in the middle          }
  249.   INPUTFIELDX      = 22;               { User Input Field                     }
  250.   INPUTFIELDY      = 20;
  251.   LOGFIELDX        = 22;               { Activity Logging                     }
  252.   LOGFIELDY        = 21;
  253.   WARNINGFIELDX    = 22;               { Warning Message Field                }
  254.   WARNINGFIELDY    = 22;
  255.   ERRORFIELDX      = 22;               { Error Message Field                  }
  256.   ERRORFIELDY      = 23;
  257.   DISASTERFIELDX   = 22;               { Disaster Message Field               }
  258.   DISASTERFIELDY   = 24;
  259.  
  260. {-------- Drive characteristics and constants communications block -----------}
  261.  
  262. VAR
  263.  
  264.   DriveLetter:          CHAR;
  265.   driveNumber:          Byte;
  266.   defaultDrive:         Byte;
  267.  
  268.   totalSectors,
  269.   sectorSize:           word;
  270.   media:                Byte;
  271.   trackSize,
  272.   numberOfHeads,
  273.   hiddenSectors,
  274.   reservedSectors,
  275.   rootDirSize:          word;
  276.   numberOfFATs:         Byte;
  277.   fatSize:              word;
  278.   clusterSize:          Byte;
  279.   firstDataSector,
  280.   firstDirectorySector,
  281.   totalDataClusters,
  282.   freeClusters,
  283.   badClusters,
  284.   usedClusters:         word;
  285.   DeviceDriverAddress: ^byte;
  286.   CurrentDirectory:     ARRAY[0..63] OF CHAR;
  287.   DiskLabel:            STRING[11];
  288.   diskCreationDate,
  289.   diskCreationTime:     word;
  290.   OEM:                  ARRAY[0..7] OF CHAR;
  291.   assignedDisk,
  292.   altAD:                Byte;
  293.  
  294.   BigFAT:               BOOLEAN;
  295.  
  296.   firstFATsector,
  297.   directorySectors:     word;
  298.  
  299. {----------------------------- Global variables ------------------------------}
  300.  
  301.   Register:             Regpack;
  302.  
  303.   oldFATindex,
  304.   newFATindex:          word;
  305.   totalFiles,
  306.   hiddenFiles,
  307.   hiddenDirectories,
  308.   inRootDirectory,
  309.   inSubdirectories,
  310.   nonContiguousFiles,
  311.   subdirectories,
  312.   movedClusters,
  313.   clustersToMove,
  314.   lostClusters,
  315.   errors,
  316.   count:                INTEGER;
  317.  
  318.   SAVEaddress,
  319.   DTAddress:           ^buffer;
  320.  
  321.   PermutationAddress,
  322.   NewFATAddress,
  323.   OldFATAddress:       ^intArray;
  324.  
  325.   RootDir:              DirectoryPointer;
  326.  
  327. {---------------------------------- miscellaneous vars -----------------------}
  328.  
  329.   hour,
  330.   min,
  331.   sec,
  332.   frac:                 INTEGER;
  333.   time:                 REAL;
  334.  
  335.   movedFieldX,
  336.   movedFieldY:          INTEGER;
  337.  
  338.   Instr:                CHAR;
  339.   AlreadyWritten:       BOOLEAN;
  340.   TmpStr:               STRING[2];
  341.   NrStr,
  342.   S40:                  Str40;
  343.   Legals:               STRING[3];
  344.   Parms:                Line;
  345.  
  346. {-----------------------------------------------------------------------------}
  347. {$I REFORMAT.IN1}  {Nijmegen .. word arithmetic                               }
  348. {$I REFORMAT.IN2}  {Toad Hall.. InLine code FOR Int25 AND Int26               }
  349. {$I REFORMAT.IN3}  {Toad Hall.. fast screen framer, FRAMER.INC                }
  350. {$I REFORMAT.IN4}  {Toad Hall.. better screen writing AND clearing, WRITEF.INC}
  351. {-----------------------------------------------------------------------------}
  352.  
  353. {----------------------- general screen I/O routines -------------------------}
  354.  
  355. PROCEDURE Beep;
  356.   BEGIN
  357.     WRITE(CHR(7));
  358.   END;                                 { of Beep }
  359.  
  360. PROCEDURE WriteLog(Text: Line);
  361.   BEGIN
  362.     WriteF(LOGFIELDX, LOGFIELDY, HiSpace);
  363.     WriteF(LOGFIELDX, LOGFIELDY, Text);
  364.   END;                                 { of WriteLog }
  365.  
  366. PROCEDURE WriteWarning(Text: Line);
  367.   BEGIN
  368.      WriteF(WARNINGFIELDX, WARNINGFIELDY, HiSpace);
  369.      WriteF(WARNINGFIELDX, WARNINGFIELDY, Text);
  370.   END;                                 { of WriteWarning }
  371.  
  372. PROCEDURE WriteError(Text: Line);
  373.   BEGIN
  374.     WriteF(ERRORFIELDX, ERRORFIELDY, HiSpace);
  375.     WriteF(ERRORFIELDX, ERRORFIELDY, Text);
  376.   END;                                 { of WriteError }
  377.  
  378. PROCEDURE WriteDisaster(Text: Line);
  379.   BEGIN
  380.     WriteF(DISASTERFIELDX, DISASTERFIELDY, HiSpace);
  381.     WriteF(DISASTERFIELDX, DISASTERFIELDY, Text);
  382.   END;                                 { of WriteDisaster }
  383.  
  384. PROCEDURE BlankFields;
  385.   BEGIN
  386.     WriteError(' ');
  387.     WriteWarning(' ');
  388.     WriteDisaster(' ');
  389.     IF Instr = 'I' THEN Register.flags := 0;
  390.   END;                                 { of BlankFields }
  391.  
  392. PROCEDURE GetInput(Prompt: Str40; VAR Instr: CHAR);
  393.   BEGIN
  394.     WriteF(INPUTFIELDX, INPUTFIELDY, HiSpace);        { really only needs 1   }
  395.     WriteF(INPUTFIELDX, INPUTFIELDY, Prompt + ': ');
  396.     Beep;
  397.     REPEAT UNTIL KeyPressed;
  398.     READ(Kbd, Instr);
  399.     Instr := UpCase(Instr);
  400.     WRITE(Instr);
  401.   END;                                 { of GetInput }
  402.  
  403. PROCEDURE Exeunt(Prompt: Str40);       { we do this a lot }
  404.   BEGIN
  405.     GetInput(Prompt, Instr);
  406.     Height := 25;
  407.     WriteF(1, 24, HiSpace);            { clear bottom line and leave screen
  408.                                          for user to contemplate }
  409.     HALT;
  410.   END;                                 { of Exeunt }
  411.  
  412. {---------------------------- timer control routines -------------------------}
  413.  
  414. PROCEDURE StartTimer;
  415. {
  416.   We want to let the user know how long REFORMAT took to do the job.
  417. }
  418.   BEGIN
  419. (* In Turbo:
  420.     with Register do begin
  421.          ah := $2C;
  422.          msdos(Register);
  423.          hour := hi(cx);
  424.          min  := lo(cx);
  425.          sec  := hi(dx);
  426.          frac := lo(dx);
  427.     end;
  428. *)
  429. {Toad Hall note:  tighter, quicker inline}
  430.   InLine(
  431.   $B4/$2C       {  mov  ah,$2C}
  432.   /$CD/$21      {  int  $21}
  433.   /$31/$C0      {  xor  ax,ax       ;clear msb}
  434.   /$86/$E8      {  xchg al,ch       ;the hour}
  435.   /$A3/>HOUR    {  mov  [>hour],ax}
  436.   /$86/$C8      {  xchg al,cl       ;the minute}
  437.   /$A3/>MIN     {  mov  [>min],ax}
  438.   /$86/$F0      {  xchg al,dh       ;the second}
  439.   /$A3/>SEC     {  mov [>sec],ax}
  440.   /$86/$D0      {  xchg al,dl       ;the fraction}
  441.   /$A3/>FRAC    {  mov [>frac],ax}
  442. );
  443.   END;                                 { of StartTimer }
  444.  
  445. PROCEDURE StopTimer;
  446. {
  447.   We want to let the user know how long REFORMAT took to do the job.
  448. }
  449.   BEGIN
  450. (* In Turbo:
  451.     with Register do begin
  452.          ah := $2C;
  453.          msdos(Register);
  454.          frac := lo(dx) - frac;
  455.          if frac < 0
  456.          then begin
  457.               frac := frac + 100;
  458.               sec  := succ(sec);
  459.          end;
  460.  
  461.          sec  := hi(dx) - sec;
  462.          if sec < 0
  463.          then begin
  464.               sec  := sec + 60;
  465.               min  := succ(min);
  466.          end
  467.          else if sec >= 60
  468.               then begin
  469.                    sec := sec - 60;
  470.                    min := pred(min);
  471.               end;
  472.  
  473.          min  := lo(cx) - min;
  474.          if min < 0
  475.          then begin
  476.               min  := min + 60;
  477.               hour := succ(hour);
  478.          end
  479.          else if min >= 60
  480.               then begin
  481.                    min  := min - 60;
  482.                    hour := pred(hour);
  483.               end;
  484.          hour := hi(cx) - hour;
  485.     end;
  486. *)
  487. {Toad Hall Note:  Tighter, faster inline.  You won't BELIEVE
  488.  what a kludge Turbo makes of the above routine.
  489. }
  490. InLine(
  491.   $B4/$2C        {  mov  ah,$2C}
  492.   /$CD/$21       {  int  $21}
  493.   /$BB/>FRAC     {  mov  bx,>frac    ;fraction offset}
  494.   /$BE/>SEC      {  mov  si,>sec     ;seconds offset}
  495.   /$31/$C0       {  xor  ax,ax       ;clear msb}
  496.   /$86/$D0       {  xchg al,dl       ;get fraction}
  497.   /$2B/$07       {  sub  ax,[bx]     ;frac = lo(dx)-frac}
  498.   /$73/$05       {  jnc  S1          ;no carry, so not <0}
  499.   /$05/$64/$00   {  add  ax,100      ;<0, adjust}
  500.   /$FF/$04       {  inc  word [si]   ;bump seconds}
  501.                  {S1:}
  502.   /$89/$07       {  mov  [bx],ax     ;save fraction}
  503.   /$BB/>MIN      {  mov  bx,>min     ;get Minute offset}
  504.   /$31/$C0       {  xor  ax,ax       ;clear msb}
  505.   /$BF/$3C/$00   {  mov  di,60       ;constant}
  506.   /$86/$F0       {  xchg al,dh       ;get seconds}
  507.   /$2B/$04       {  sub  ax,[si]     ;sec = hi(dx)-sec}
  508.   /$73/$06       {  jnc  S2          ;not <0}
  509.   /$01/$F8       {  add  ax,di       ;<0, adjust}
  510.   /$FF/$07       {  inc  word [bx]   ;min=min+1}
  511.   /$EB/$08       {  jmp short S3}
  512.                  {S2:}
  513.   /$39/$F8       {  cmp  ax,di       ;>=60?}
  514.   /$72/$04       {  jb   S3          ; nope}
  515.   /$29/$F8       {  sub  ax,di       ; sec=sec-60}
  516.   /$FF/$0F       {  dec  word [bx]   ;min=min-1}
  517.                  {S3:}
  518.   /$89/$04       {  mov  [si],ax     ;save seconds}
  519.   /$BE/>HOUR     {  mov  si,>hour    ;hour offset}
  520.   /$31/$C0       {  xor  ax,ax       ;clear msb}
  521.   /$86/$C8       {  xchg al,cl       ;get minutes}
  522.   /$2B/$07       {  sub  ax,[bx]     ;min=lo(cx)-min}
  523.   /$73/$06       {  jnc  S4          ; not below 0}
  524.   /$01/$F8       {  add  ax,di       ;min=min+60}
  525.   /$FF/$04       {  inc  word [si]   ;hour=hour+1}
  526.   /$EB/$08       {  jmp short S5}
  527.                  {S4:}
  528.   /$39/$F8       {  cmp  ax,di       ;>=60?}
  529.   /$72/$04       {  jb   S5          ; nope}
  530.   /$29/$F8       {  sub  ax,di       ;min=min-60}
  531.   /$FF/$0C       {  dec  word [si]   ;hour=hour-1}
  532.                  {S5:}
  533.   /$89/$07       {  mov  [bx],ax     ;save minutes}
  534.   /$31/$C0       {  xor  ax,ax       ;clear msb}
  535.   /$86/$E8       {  xchg al,ch       ;get hour}
  536.   /$2B/$04       {  sub  ax,[si]     ;hour=hi(cx)-hour}
  537.   /$89/$04       {  mov  [si],ax}
  538. );
  539.   END;                                 { of StopTimer }
  540.  
  541. {$I REFORMAT.IN5}   {Nijmegen  .. disk, FAT, directory, misc. routines }
  542.