home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MADTRB15.ZIP / DIRECTRY.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1985-07-31  |  20.0 KB  |  654 lines

  1. {                 *****     Directories From Turbo     *****
  2.  
  3.    Written By:  Drew Letcher                                3/23/85
  4.                 Iowa Software Associates
  5.                 104 Hawkeye Ct.
  6.                 Iowa City, IA  52240
  7.                 (319) 337-4782
  8.  
  9.    This program gives example routines for accessing the DOS 2.1 directories,
  10.    and examples for switching drives and directories in Turbo programs, for
  11.    reading and setting a files attribute byte, for getting a disk's space
  12.    information, and for accessing the command line when running Turbo programs.
  13.    The file itself is a ready to compile/run Turbo program that gives a
  14.    directory listing and some disk status information.
  15.  
  16.    All these routines use the Turbo MSDOS() function which accesses the DOS
  17.    software interrupt 21h, see section B.2.2 in the Turbo manual.  The
  18.    functions used inside this interrupt are as follows:
  19.  
  20.          get first directory entry               4Eh
  21.          get next directory entry                4Fh
  22.          get the Disk Transfer Address           2Fh
  23.           ( where DOS returns info to you )
  24.          get drive total/free space              36h
  25.  
  26.          default drive designator                19h
  27.          change default drive                    0Eh
  28.  
  29.          get current directory                   47h
  30.          make a directory                        39h
  31.          remove a directory                      3Ah
  32.          change directory                        3Bh
  33.  
  34.          get/set a files attributes              43h
  35.  
  36.  
  37.    This program has redundant declarations and does things in a straight
  38.    forward so as to make these routines easily understandable and
  39.    transportable to your own programs.  For other information see the DOS
  40.    Technical Reference Manual, or any of the good books availble on the
  41.    DOS programmers' level.
  42. }
  43.  
  44. {.pa}
  45.  
  46. PROGRAM  DirectoriesFromTurbo;
  47. {  ***  set compiler directives  ***  }
  48. {  Appendix E of the TurboPascal manual  }
  49.  
  50. {$B+}  {  set con/term as standard I/O device  }
  51. {$C+}  {  use of ^C and ^S during standard I/O  }
  52. {$I+}  {  disk I/O error checking  }
  53. {$R-}  {  array index range checking  }
  54. {$V+}  {  type checking of string parameters }
  55. {$U+}  {  user interrupt with ^C  }
  56. {$K+}  {  check stack space for variables during procedure calls }
  57.  
  58.  
  59. TYPE
  60.    path           =  string[ 64 ];
  61.    name           =  string[ 13 ];
  62.    directoryinfo  =  RECORD
  63.                      filename    :  name;
  64.                      size        :  real;
  65.                      time        :  string[ 8 ];
  66.                      date        :  string[ 8 ];
  67.                      attribute   :  string[ 7 ];
  68.                      END;
  69.  
  70.    memoryaddress  =  ( segment, offset );
  71.    address        =  ARRAY[ memoryaddress ] OF integer;
  72.    directorytype  =  string[ 64 ];
  73.    drivedesignator     =  string[ 2 ];
  74.  
  75.  
  76. VAR
  77.    Searchname     :  name;
  78.    DirEntry       :  directoryinfo;
  79.    DirFlag        :  boolean;
  80.    Directory      :  directorytype;
  81.    DirSize,
  82.    TotalSpace,
  83.    FreeSpace      :  real;
  84.    Drive          :  integer;
  85.  
  86. { end Main routine declarations  }
  87. {.pa}
  88.  
  89.  
  90. PROCEDURE  CheckCommandLine( VAR SearchName  :  name );
  91.  
  92. {  The commandline is located at CSeg:$0080 and contains everything after
  93.    the program name that you type to invoke a Turbo program, including the
  94.    space right after the program name.  If you want to use the command line
  95.    save it right away.  The maximum length of the command line is 127
  96.    characters.  The length of the command line is at CSeg:$0080, and the
  97.    actual string starts at CSeg:$0081.  So a string variable will automatically
  98.    be set to the length of the line typed in by a user.  }
  99.  
  100.  
  101.    VAR
  102.       I          :  integer;
  103.       TempLine   :  string[ 30 ];
  104.       ComLine    :  string[ 30 ] ABSOLUTE CSeg:$0080;
  105.  
  106.    BEGIN
  107.    IF Length( ComLine ) = 0 THEN
  108.       BEGIN
  109.       SearchName := '????????.???' + chr(0);    {  will search for all files  }
  110.       END
  111.    ELSE     { search for files matching the filename in the command line,
  112.               this routine doesn't check for a path name or expand asteriks.  }
  113.       BEGIN
  114.       TempLine := ComLine;
  115.       WHILE TempLine[ 1 ] = ' ' DO
  116.          Delete( TempLine, 1, 1 );
  117.  
  118.       I := 0;
  119.       WHILE ( I < 13 ) AND ( TempLine[ I ] <> chr(0) ) DO
  120.          BEGIN
  121.          I := I + 1;
  122.          SearchName[ I ] := UpCase( TempLine[ I ] );
  123.          {  does grab chr(0) as the last character  }
  124.          END;
  125.       END;  {  Else  }
  126.    END;  {  **  Procedure CheckCommandLine  **  }
  127. {.pa}
  128.  
  129.  
  130. FUNCTION  DefaultDrive  :  drivedesignator;
  131. { returns the default drive designator.   e.g.  A:  }
  132.  
  133.    TYPE
  134.       registertype  =  RECORD
  135.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  136.                        END;
  137.  
  138.    VAR
  139.       Registers  :  registertype;
  140.  
  141.    BEGIN
  142.    WITH  Registers  DO
  143.       BEGIN
  144.       AX := $19 shl 8;
  145.       MSDOS( Registers );                  { return AX = 0 is drive A, etc. }
  146.       DefaultDrive := Chr( 65 + Lo( AX ) ) + ':';
  147.       END;
  148.    END;  {  **  Function DefaultDrive  **  }
  149.  
  150.  
  151. PROCEDURE  ChangeDefaultDrive(  DriveLetter  :  drivedesignator  );
  152. {  parameter can be:  a, A, a:, or A:   where "a" can be any valid
  153.    drive letter.  }
  154.  
  155.    TYPE
  156.       registertype  =  RECORD
  157.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  158.                        END;
  159.  
  160.    VAR
  161.       Registers  :  registertype;
  162.  
  163.    BEGIN
  164.    WITH Registers DO
  165.       BEGIN
  166.       AX := $0E shl 8;
  167.       DX := Ord( UpCase( DriveLetter[ 1 ] ) ) - 65;     {  A: is 0, etc.  }
  168.       MSDOS( Registers );
  169.       IF DX < 0 THEN  writeln( 'Invalid Drive Designator', DriveLetter );
  170.       END;
  171.    END;  {  **  Procedure  ChangeDefaultDrive  **  }
  172. {.pa}
  173.  
  174.  
  175. PROCEDURE  GetCurrentDirectory( VAR CurrentDirectory  :  directorytype );
  176. {  gets the path name of the current directory, doesn't include the drive
  177.    designator.   The routine gives DOS a 64 byte location in memory in
  178.    which to store the path.  }
  179.  
  180.    TYPE
  181.       registertype  =  RECORD
  182.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  183.                        END;
  184.  
  185.    VAR
  186.       Registers  :  registertype;
  187.       I,
  188.       Value,
  189.       CurDirSeg,
  190.       CurDirOfs  :  integer;
  191.  
  192.    BEGIN
  193.  
  194.    CurDirSeg := Seg( CurrentDirectory );
  195.    CurDirOfs := Ofs( CurrentDirectory );
  196.    WITH Registers DO
  197.       BEGIN
  198.       AX := $47 shl 8;
  199.       DX := 0;
  200.       DS := CurDirSeg;
  201.       SI := CurDirOfs + 1;
  202.       MSDOS( Registers );
  203.       END;  {  With  }
  204.  
  205.    CurrentDirectory := '';
  206.    I := 1;
  207.    Value := Mem[ CurDirSeg : CurDirOfs + I ];
  208.    WHILE ( I <= 64 ) AND ( Value > 33 ) AND ( Value < 128 ) DO
  209.       BEGIN
  210.       Mem[ CurDirSeg : CurDirOfs ] := Mem[ CurDirSeg : CurDirOfs ] + 1;
  211.       I := I + 1;
  212.       Value := Mem[ CurDirSeg : CurDirOfs + I ];
  213.       END;
  214.    CurrentDirectory := '\' + CurrentDirectory;
  215.    END;  {  **  Procedure GetCurrentDirectory  **  }
  216. {.pa}
  217.  
  218.  
  219. FUNCTION  ChangeDirectory( VAR NewDirectory : directorytype ) : boolean;
  220. {  The directory path can contain the drive on which to change the
  221.    directory.  }
  222.  
  223.    TYPE
  224.       registertype  =  RECORD
  225.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  226.                        END;
  227.  
  228.    VAR
  229.       Registers  :  registertype;
  230.  
  231.    BEGIN
  232.    WITH Registers DO
  233.       BEGIN
  234.       AX := $3B shl 8;
  235.       DS := Seg( NewDirectory );
  236.       DX := Ofs( NewDirectory ) +1;
  237.       MSDOS( Registers );
  238.       IF AX = 5 THEN
  239.          BEGIN
  240.          ChangeDirectory := false;
  241.          writeln( 'Change Directory Failed - Bad Directory Path' );
  242.          END
  243.       ELSE
  244.          ChangeDirectory := true;
  245.       END;  {  With  }
  246.    END;  {  **  Function ChangeDirectory  **  }
  247.  
  248.  
  249. {.pa}
  250. FUNCTION  MakeDirectory( VAR NewDirectory : directorytype ) : boolean;
  251.    TYPE
  252.       registertype  =  RECORD
  253.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  254.                        END;
  255.    VAR
  256.       Registers  :  registertype;
  257.  
  258.    BEGIN
  259.    WITH Registers DO
  260.       BEGIN
  261.       AX := $39 shl 8;
  262.       DS := Seg( NewDirectory );
  263.       DX := Ofs( NewDirectory ) +1;
  264.       MSDOS( Registers );
  265.       IF AX = 5 THEN
  266.          BEGIN
  267.          MakeDirectory := false;
  268.          writeln( 'Make Directory Failed - Bad or Existing Directory Path' );
  269.          END
  270.       ELSE
  271.          MakeDirectory := true;
  272.       END;  {  With  }
  273.    END;  {  **  Function MakeDirectory **  }
  274.  
  275.  
  276. FUNCTION  RemoveDirectory( VAR Directory : directorytype ) : boolean;
  277.    TYPE
  278.       registertype  =  RECORD
  279.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  280.                        END;
  281.    VAR
  282.       Registers  :  registertype;
  283.  
  284.    BEGIN
  285.    WITH Registers DO
  286.       BEGIN
  287.       AX := $3A shl 8;
  288.       DS := Seg( Directory );
  289.       DX := Ofs( Directory ) +1;
  290.       MSDOS( Registers );
  291.       IF AX = 5 THEN
  292.          BEGIN
  293.          RemoveDirectory := false;
  294.          writeln( 'Remove Directory Failed - Bad or Non-empty Directory Path' );
  295.          END
  296.       ELSE
  297.          RemoveDirectory := true;
  298.       END;  {  With  }
  299.    END;  {  **  Function RemoveDirectory **  }
  300. {.pa}
  301.  
  302.  
  303. PROCEDURE  GetAttrib(      PathName   :  path;      {  full path name  }
  304.                        VAR Attribute  :  integer );
  305.  
  306.    TYPE
  307.       registertype  =  RECORD
  308.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  309.                        END;
  310.  
  311.    VAR
  312.       Registers  :  registertype;
  313.  
  314.    BEGIN
  315.    WITH Registers DO
  316.       BEGIN
  317.       AX := $43 shl 8 + 0;
  318.       DS := Seg( PathName );
  319.       DX := Ofs( PathName ) + 1;
  320.       MSDOS( Registers );
  321.       Attribute := CX;
  322.       END;  {  With  }
  323.    END;  {  **  Procedure GetAttrib  **  }
  324.  
  325. {  Attribute byte values:
  326.                            0  -  normal read/write
  327.                            1  -  read only
  328.                            2  -  hidden
  329.                            4  -  system file
  330.                            8  -  volume label entry
  331.                           16  -  directory entry
  332.                           32  -  bit = 0 - Archived,
  333.                                      = 1 - not archived  }
  334.  
  335.  
  336. PROCEDURE  SetAttrib(  PathName   :  path;      {  full path name  }
  337.                        Attribute  :  integer );
  338.  
  339.    TYPE
  340.       registertype  =  RECORD
  341.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  342.                        END;
  343.  
  344.    VAR
  345.       Registers  :  registertype;
  346.  
  347.    BEGIN
  348.    WITH Registers DO
  349.       BEGIN
  350.       AX := $43 shl 8 + 1;
  351.       DS := Seg( PathName );
  352.       DX := Ofs( PathName ) + 1;
  353.       CX := Attribute;
  354.       MSDOS( Registers );
  355.       IF AX = 3 THEN
  356.          writeln( AX, ' Path Not Found or Attribute Already Set' );
  357.       IF AX = 5 THEN
  358.          writeln( AX, ' Access Denied for File Type' );
  359.       END;  {  With  }
  360.    END;  {  **  Procedure SetAttrib  **  }
  361. {.pa}
  362.  
  363.  
  364. FUNCTION   GetDriveSpace(     Drive       : integer;
  365.                           VAR TotalSpace,
  366.                               FreeSpace   : real      ) : boolean;
  367.  
  368.    TYPE
  369.       registertype  =  RECORD
  370.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  371.                        END;
  372.  
  373.    VAR
  374.       Registers          :  registertype;
  375.       TotalClusters,
  376.       FreeClusters,
  377.       SectorsPerCluster,
  378.       BytesPerSector     :  real;
  379.  
  380.    BEGIN
  381.    WITH Registers DO
  382.       BEGIN
  383.       AX := $36 shl 8;
  384.       DX := Drive;
  385.       MSDOS( Registers );
  386.       IF AX = $FFFF THEN
  387.          BEGIN
  388.          GetDriveSpace := false;
  389.          writeln( 'Invalid Drive Designator' );
  390.          END
  391.       ELSE
  392.          BEGIN
  393.          GetDriveSpace := true;
  394.          TotalClusters := DX;
  395.          FreeClusters := BX;
  396.          SectorsPerCluster := AX;
  397.          BytesPerSector := CX;
  398.          TotalSpace := TotalClusters * SectorsPerCluster * BytesPerSector;
  399.          FreeSpace := FreeClusters * SectorsPerCluster * BytesPerSector;
  400.          END;
  401.       END;  {  With  }
  402.    END;  {  **  Function GetDriveSpace  **  }
  403. {.pa}
  404.  
  405.  
  406. PROCEDURE  GetDirEntry( VAR SearchName  :  name;
  407.                         VAR DirEntry    :  directoryinfo;
  408.                         VAR DirFlag     :  boolean        );
  409.  
  410.  
  411. {  Passes the next directory entry back to the calling routine.  IF DirFlag
  412.    is false Directory will get the first directory entry,  if it is true
  413.    Directory will get the next directory entry.  If there are no more
  414.    directory entries, Directory will set the value of DirFlag to false.
  415.    Thus, DirFlag must be set when calling Directory, and you must check
  416.    DirFlag upon returning.  }
  417.  
  418.    TYPE
  419.       registertype  =  RECORD
  420.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  421.                        END;
  422.       memoryaddress  =  ( segment, offset );
  423.       address        =  ARRAY[ memoryaddress ] OF integer;
  424.  
  425.  
  426.    VAR
  427.      registers  :  registertype;
  428.  
  429.  
  430.    PROCEDURE  GetDTA( VAR DTA : address );
  431.    {  get the Disk Transfer Address where DOS will return the directory
  432.       information.   }
  433.  
  434.       TYPE
  435.          registertype  =  RECORD
  436.                           AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  437.                           END;
  438.  
  439.       VAR
  440.          Registers  :  registertype;
  441.  
  442.       BEGIN
  443.       WITH Registers DO
  444.          BEGIN
  445.          AX := $2F shl 8;
  446.          MSDOS( Registers );
  447.          DTA[ segment ] := ES;
  448.          DTA[ offset ] := BX;
  449.          END;
  450.       END;  {  **  Procedure GetDTA  **  }
  451. {.pa}
  452.  
  453.  
  454.    PROCEDURE  GetEntryFromDTA( VAR DirEntry : directoryinfo );
  455.  
  456.    {  GetEntry gets the directory info from the Disk Transfer Area in
  457.       memory as follows:
  458.  
  459.           DTA address +        Contents
  460.               21                 attribute
  461.               22-23              creation time
  462.               24-25              creation date
  463.               26-27              low bytes file size
  464.               28-29              high bytes file size
  465.               30-42              filename, upto 13 bytes terminated by chr(0)
  466.  
  467.    }
  468.  
  469.       VAR
  470.          registers       :  registertype;
  471.          DTA             :  address;
  472.          DTAseg,
  473.          DTAofs,
  474.          I,
  475.          Temp            :  integer;
  476.          Hour, Min, Sec,
  477.          Month, Day      :  string[ 2 ];
  478.          Year            :  string[ 4 ];
  479.  
  480.       BEGIN
  481.          GetDTA( DTA );
  482.          DTAseg := DTA[ segment ];
  483.          DTAofs := DTA[ offset ];
  484.  
  485.          WITH DirEntry DO
  486.             BEGIN
  487.             {  get the attribute byte  }
  488.             attribute := '.......';
  489.             Temp := Mem[ DTAseg : DTAofs + 21 ];
  490.             IF ( Temp AND 223 ) = 0 THEN
  491.                attribute := 'RW.....';                { regular Read/Write }
  492.             IF ( Temp AND 1 ) = 1 THEN
  493.                Insert( 'R', attribute, 1 );           { Read only file }
  494.             IF ( Temp AND 2 ) = 2 THEN
  495.                Insert( 'H', attribute, 3 );           { Hidden file }
  496.             IF ( Temp AND 4 ) = 4 THEN
  497.                Insert( 'S', attribute, 4 );           { System file }
  498.             IF ( Temp AND 8 ) = 8 THEN
  499.                Insert( 'V', attribute, 5 );           { root Volume label }
  500.             IF ( Temp AND 16 ) = 16 THEN
  501.                Insert( 'D', attribute, 6 );           { subDirectory }
  502.             IF ( Temp AND 32 ) = 0 THEN
  503.                Insert( 'A', attribute, 7 );           { Archived }
  504. {.pa}
  505.             {  get the creation time  }
  506.             Temp := Mem[ DTAseg : DTAofs + 23 ];
  507.             str( ( Temp shr 3 ):2, Hour );
  508.             Temp := 8 * ( Temp AND 3 );
  509.             Temp := Temp + ( Mem[ DTAseg : DTAofs + 22 ] shr 5 );
  510.             str( Temp, Min );
  511.             IF Length( Min ) < 2 THEN
  512.                Min := '0' + Min;
  513.             Temp := Mem[ DTAseg : DTAofs + 22 ];
  514.             str( ( ( Temp AND 31 ) * 2 ):2, Sec );
  515.             time := Hour + ':' + Min;           { who cares about seconds? }
  516.  
  517.             {  get the creation date }
  518.             Temp := Mem[ DTAseg : DTAofs + 25 ];
  519.             str( ( 80 + ( Temp shr 1 ) ):2, Year );
  520.             Temp := 8 * ( Temp AND 1 );
  521.             Temp := Temp + ( Mem[ DTAseg : DTAofs + 24 ] shr 5 );
  522.             str( Temp:2, Month );
  523.             Temp := Mem[ DTAseg : DTAofs + 24 ];
  524.             str( ( Temp AND 31 ), Day );
  525.             IF Length( Day ) < 2 THEN
  526.                Day := '0' + Day;
  527.             date := Month + '-' + Day + '-' + Year;
  528.  
  529.  
  530.             {  get the filesize }
  531.             size := 0;
  532.             size := Mem[ DTAseg : DTAofs + 26 ];
  533.             size := size + Mem[ DTAseg : DTAofs + 27 ] * 256.0;
  534.             size := size + Mem[ DTAseg : DTAofs + 28 ] * 65536.0;
  535.             size := size + Mem[ DTAseg : DTAofs + 29 ] * 16777200.0;
  536.  
  537.             {  get the filename and store in DirEntry  }
  538.             filename := '';
  539.             I := 30;
  540.             Temp := Mem[ DTAseg : DTAofs + I ];
  541.             WHILE ( I <= 41 ) AND ( Temp <> 0 ) DO
  542.                BEGIN
  543.                filename := filename + chr( Temp );
  544.                I := I + 1;
  545.                Temp := Mem[ DTAseg : DTAofs + I ];
  546.                END;  {  While  }
  547.            END;  {  With  }
  548.       END;   {  ***  Procedure GetEntry  ***  }
  549. {.pa}
  550.  
  551.    BEGIN   {  *****  Directory Routine  *****  }
  552.       WITH Registers DO
  553.          BEGIN
  554.          IF DirFlag = false THEN      {  get the first directory entry  }
  555.             BEGIN
  556.             DirFlag := true;
  557.             DS := Seg( SearchName );
  558.             DX := Ofs( SearchName ) + 1;
  559.             CX := 31;
  560.             AX := $4E shl 8;
  561.             MSDOS( Registers );
  562.             GetEntryFromDTA( DirEntry );
  563.             END
  564.          ELSE                          {  else get the next directory entry  }
  565.             BEGIN                      {  DOS remembers the last file        }
  566.             AX := $4F shl 8;           {  searched for.                      }
  567.             MSDOS( Registers );
  568.             IF AX = 0 THEN             {  AX returns 0 as long as there are }
  569.                GetEntryFromDTA( DirEntry )       {  more directory entries. }
  570.             ELSE
  571.                DirFlag := false;
  572.             END;  {  Outer If  }
  573.  
  574.          END;  {  With Registers  }
  575.    END;  {  ***  Procedure  Directory  ***  }
  576.  
  577.  
  578. PROCEDURE  FormatFilename(  VAR  Filename  :  name  );
  579.  
  580. VAR
  581.    LengthName,
  582.    TrailingBlanks,
  583.    I, J             :  integer;
  584.  
  585. BEGIN
  586.    LengthName := Length( Filename );
  587.    TrailingBlanks := 12 - LengthName;
  588.    I := 1;
  589.    WHILE ( I < 9 ) AND ( I < LengthName ) DO
  590.       BEGIN
  591.       IF ( FileName[ I ] = '.' ) THEN
  592.          BEGIN
  593.          FOR J := I TO 8 DO
  594.             Insert( ' ', Filename, J );
  595.          I := 9;
  596.          END;
  597.       I := I + 1;
  598.       END;  {  While  }
  599.  
  600.    FOR I := Length( Filename ) TO 12 DO
  601.       Filename := Filename + ' ';
  602. END;  {  **  Procedure FormatFilename  **  }
  603. {.pa}
  604.  
  605.  
  606. {  **  Main routine declarations  **  }
  607.  
  608. VAR
  609.   NumberFiles    :  integer;
  610.   Attribute      :  integer;
  611.   PathName       :  path;
  612.   DriveLetter   :  drivedesignator;
  613.  
  614. {  **  end Main routine declarations  **  }
  615.  
  616.  
  617. BEGIN  {  **  Main Routine  **  }
  618.  
  619. CheckCommandLine( SearchName );
  620.  
  621. DriveLetter := DefaultDrive;
  622. GetCurrentDirectory( Directory );
  623. writeln( 'Current Directory: ', DriveLetter, Directory );
  624. writeln;
  625.  
  626. DirFlag := false;                  {  get the first directory entry  }
  627. GetDirEntry( SearchName, DirEntry, DirFlag );
  628.  
  629. NumberFiles := 0;
  630. DirSize := 0;
  631. WHILE  DirFlag = true DO
  632.    BEGIN
  633.    WITH DirEntry DO
  634.       BEGIN
  635.       FormatFilename( filename );
  636.       writeln( filename:12, size:10:0, attribute:10, date:12, time:10 );
  637.       IF attribute[ 1 ] = 'R' THEN  NumberFiles := NumberFiles + 1;
  638.       DirSize := DirSize + size;
  639.       GetDirEntry( SearchName, DirEntry, DirFlag );
  640.       END;  {  With  }
  641.    END;  {  While  }
  642.  
  643. {  get drive total / free space   }
  644. Drive := 0;  {  current drive  }
  645. IF GetDriveSpace( Drive, TotalSpace, FreeSpace ) THEN
  646.    BEGIN
  647.    writeln;
  648.    writeln( TotalSpace:8:0, '  Bytes Total Disk Space' );
  649.    writeln( FreeSpace:8:0,  '  Bytes Free' );
  650.    writeln( DirSize:8:0,    '  Bytes This Listing in ',
  651.             NumberFiles:3,  ' Files'                      );
  652.    END;
  653. END.
  654.