home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / DIRECTRY.ZIP / DIRECTRY.PAS
Encoding:
Pascal/Delphi Source File  |  1986-03-28  |  25.4 KB  |  801 lines

  1. {                 *****     Directories From Turbo     *****
  2. Source: PConnecticut BBS 4/13/85
  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. modifications by Scott Daniels
  10.  07/02/85 - set up as INClude file vice complete program
  11.             make CheckCommandLine more general - now only gets Tail;
  12.  07/05    - Search spec is now set in another procedure;
  13.  07/19    - quits with msg ('no files found') if Find First yields AX<>0;
  14.            corrected time calculation (was off by 32 mins);
  15.            reversed use of 'Archive' bit to conform with MSDOS use. If set
  16.            (=1), means file has changed and should be saved or 'Archived'.
  17.  10/01    - GetSearchName changes default drive if passed just drive letter
  18.            (eg Directry B:)
  19.  
  20.  
  21.    This program gives example routines for accessing the DOS 2.1  directories,
  22.    and  examples  for switching drives and directories in Turbo programs,  for
  23.    reading and setting a files attribute byte,  for  getting  a  disk's  space
  24.    information,  and  for  accessing  the  command  line  when  running  Turbo
  25.    programs.  The file itself is a ready to  compile/run  Turbo  program  that
  26.    gives a directory listing and some disk status information.
  27.  
  28.    All  these  routines  use the Turbo MSDOS() function which accesses the DOS
  29.    software interrupt  21h,  see  section  B.2.2  in  the  Turbo  manual.  The
  30.    functions used inside this interrupt are as follows:
  31.  
  32.          get first directory entry               4Eh
  33.          get next directory entry                4Fh
  34.          get the Disk Transfer Address           2Fh
  35.           ( where DOS returns info to you )
  36.          get drive total/free space              36h
  37.  
  38.          default drive designator                19h
  39.          change default drive                    0Eh
  40.  
  41.          get current directory                   47h
  42.          make a directory                        39h
  43.          remove a directory                      3Ah
  44.          change directory                        3Bh
  45.  
  46.          get/set a files attributes              43h
  47.  
  48.  
  49.    This  program  has  redundant  declarations  and  does things in a straight
  50.    forward manner so as to  make  these  routines  easily  understandable  and
  51.    transportable  to  your  own  programs.  For  other information see the DOS
  52.    Technical Reference Manual,  or any of the good books availble on  the  DOS
  53.    programmers' level.
  54. }
  55.  
  56. {.pa}
  57.  
  58. {PROGRAM  DirectoriesFromTurbo;}
  59. {  ***  set compiler directives  ***  }
  60. {  Appendix E of the TurboPascal manual  }
  61.  
  62. {$B+}  {  set con/term as standard I/O device  }
  63. {$C+}  {  use of ^C and ^S during standard I/O  }
  64. {$I+}  {  disk I/O error checking  }
  65. {$R-}  {  array index range checking  }
  66. {$V+}  {  type checking of string parameters }
  67. {$U+}  {  user interrupt with ^C  }
  68. {$K+}  {  check stack space for variables during procedure calls }
  69.  
  70.  
  71. TYPE
  72.    path           =  string[ 64 ];
  73.    name           =  string[ 13 ];     {eg 12345678.xxx + chr(0)}
  74.    directoryinfo  =  RECORD
  75.                      filename    :  name;
  76.                      size        :  real;
  77.                      time        :  string[ 8 ];
  78.                      date        :  string[ 8 ];
  79.                      attribute   :  string[ 7 ];
  80.                      END;
  81.  
  82.    memoryaddress  =  ( segment, offset );
  83.    address        =  ARRAY[ memoryaddress ] OF integer;
  84.    directorytype  =  string[ 64 ];
  85.    drivedesignator     =  string[ 2 ];
  86.  
  87.    tailtype       = string[30];      {# chars for command line}
  88.    string12       = string[12];
  89.  
  90.  
  91. const
  92.    Default_SearchName     :  name= '????????.???';
  93.  
  94. var
  95.    CmdTail        : name;
  96.    DirEntry       :  directoryinfo;
  97.    DirFlag        :  boolean;
  98.    Directory      :  directorytype;
  99.    DirSize,
  100.    TotalSpace,
  101.    FreeSpace      :  real;
  102.    Drive          :  integer;
  103.    SearchName     : name;
  104.  
  105. { end Main routine declarations  }
  106. {.pa}
  107.  
  108.  
  109. function CheckCommandLine: name;
  110.  
  111. {  The  commandline is located at CSeg:$0080 and contains everything after the
  112.    program name that you type to invoke a Turbo program,  including the  space
  113.    right  after the program name.  If you want to use the command line save it
  114.    right away.  The maximum length of the command line is 127 characters.  The
  115.    length of the command line is at CSeg:$0080,  and the actual string  starts
  116.    at  CSeg:$0081.  So  a  string  variable  will  automatically be set to the
  117.    length of the line typed in by a user. }
  118.  
  119. { search for files matching the filename in the command line, on current drive;
  120.    this routine doesn't check for a path name or expand asteriks.  }
  121.  
  122.    VAR
  123.       I          :  integer;
  124.       TempLine   :  Tailtype;
  125.       ComLine    :  Tailtype ABSOLUTE CSeg:$0080;
  126.       TempName   :  tailtype;
  127.  
  128.    BEGIN
  129.  
  130.       TempLine := ComLine;
  131. {      writeln('1. TAIL >',TempLine,'<');}
  132.       TempName := '';
  133.       WHILE TempLine[1] = ' ' DO        {locate first non-blank}
  134.          Delete(TempLine,1,1);
  135.  
  136. {      write('2. TAIL >');
  137.       for i:= 1 to length(TempLine) do write(TempLine[i],'=',ord(TempLine[i]),'/');
  138.       writeln('<'); }
  139.  
  140.       I := 0;
  141.       WHILE (I < length(TempLine)) AND (TempLine[I] <> chr(0))
  142.       { and (TempLine[I] in ['!'..'z'])}   DO
  143.          BEGIN
  144.          I := I + 1;
  145.          TempName := TempName + UpCase(TempLine[I]);
  146.                              {  does grab chr(0) as the last character  }
  147.          END;
  148. {      writeln('TAIL >',TempName,'<');}
  149.       CheckCommandLine := TempName;
  150.  
  151.    END;  {  **  Procedure CheckCommandLine  **  }
  152. {.pa}
  153.  
  154.  
  155. FUNCTION  DefaultDrive  :  drivedesignator;
  156. { returns the default drive designator.   e.g.  A:  }
  157.  
  158.    TYPE
  159.       registertype  =  RECORD
  160.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  161.                        END;
  162.  
  163.    VAR
  164.       Registers  :  registertype;
  165.  
  166.    BEGIN
  167.    WITH  Registers  DO
  168.       BEGIN
  169.       AX := $19 shl 8;
  170.       MSDOS( Registers );                  { return AX = 0 is drive A, etc. }
  171.       DefaultDrive := Chr( 65 + Lo( AX ) ) + ':';
  172.       END;
  173.    END;  {  **  Function DefaultDrive  **  }
  174.  
  175.  
  176. PROCEDURE  ChangeDefaultDrive(  DriveLetter  :  drivedesignator  );
  177. {  parameter can be:  a, A, a:, or A:   where "a" can be any valid
  178.    drive letter.  }
  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.  
  188.    BEGIN
  189.    WITH Registers DO
  190.       BEGIN
  191.       AX := $0E shl 8;
  192.       DX := Ord( UpCase( DriveLetter[ 1 ] ) ) - 65;     {  A: is 0, etc.  }
  193.       MSDOS( Registers );
  194.       IF DX < 0 THEN  writeln( 'Invalid Drive Designator', DriveLetter );
  195.       END;
  196.    END;  {  **  Procedure  ChangeDefaultDrive  **  }
  197. {.pa}
  198.  
  199.  
  200. PROCEDURE  GetCurrentDirectory( VAR CurrentDirectory  :  directorytype );
  201. { gets the path name of the  current  directory,  doesn't  include  the  drive
  202.    designator.  The routine gives DOS a 64 byte location in memory in which to
  203.    store the path. } 
  204.  
  205.    TYPE
  206.       registertype  =  RECORD
  207.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  208.                        END;
  209.  
  210.    VAR
  211.       Registers  :  registertype;
  212.       I,
  213.       Value,
  214.       CurDirSeg,
  215.       CurDirOfs  :  integer;
  216.  
  217.    BEGIN
  218.  
  219.    CurDirSeg := Seg( CurrentDirectory );
  220.    CurDirOfs := Ofs( CurrentDirectory );
  221.    WITH Registers DO
  222.       BEGIN
  223.       AX := $47 shl 8;
  224.       DX := 0;
  225.       DS := CurDirSeg;
  226.       SI := CurDirOfs + 1;
  227.       MSDOS( Registers );
  228.       END;  {  With  }
  229.  
  230.    CurrentDirectory := '';
  231.    I := 1;
  232.    Value := Mem[ CurDirSeg : CurDirOfs + I ];
  233.    WHILE ( I <= 64 ) AND ( Value > 33 ) AND ( Value < 128 ) DO
  234.       BEGIN
  235.       Mem[ CurDirSeg : CurDirOfs ] := Mem[ CurDirSeg : CurDirOfs ] + 1;
  236.       I := I + 1;
  237.       Value := Mem[ CurDirSeg : CurDirOfs + I ];
  238.       END;
  239.    CurrentDirectory := '\' + CurrentDirectory;
  240.    END;  {  **  Procedure GetCurrentDirectory  **  }
  241. {.pa}
  242.  
  243.  
  244. FUNCTION  ChangeDirectory( VAR NewDirectory : directorytype ) : boolean;
  245. { The directory path can contain the drive on which to change the directory. } 
  246.  
  247.    TYPE
  248.       registertype  =  RECORD
  249.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  250.                        END;
  251.  
  252.    VAR
  253.       Registers  :  registertype;
  254.  
  255.    BEGIN
  256.    WITH Registers DO
  257.       BEGIN
  258.       AX := $3B shl 8;
  259.       DS := Seg( NewDirectory );
  260.       DX := Ofs( NewDirectory ) +1;
  261.       MSDOS( Registers );
  262.       IF AX = 5 THEN
  263.          BEGIN
  264.          ChangeDirectory := false;
  265.          writeln( 'Change Directory Failed - Bad Directory Path' );
  266.          END
  267.       ELSE
  268.          ChangeDirectory := true;
  269.       END;  {  With  }
  270.    END;  {  **  Function ChangeDirectory  **  }
  271.  
  272.  
  273. {.pa}
  274. FUNCTION  MakeDirectory( VAR NewDirectory : directorytype ) : boolean;
  275.    TYPE
  276.       registertype  =  RECORD
  277.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  278.                        END;
  279.    VAR
  280.       Registers  :  registertype;
  281.  
  282.    BEGIN
  283.    WITH Registers DO
  284.       BEGIN
  285.       AX := $39 shl 8;
  286.       DS := Seg( NewDirectory );
  287.       DX := Ofs( NewDirectory ) +1;
  288.       MSDOS( Registers );
  289.       IF AX = 5 THEN
  290.          BEGIN
  291.          MakeDirectory := false;
  292.          writeln( 'Make Directory Failed - Bad or Existing Directory Path' );
  293.          END
  294.       ELSE
  295.          MakeDirectory := true;
  296.       END;  {  With  }
  297.    END;  {  **  Function MakeDirectory **  }
  298.  
  299.  
  300. FUNCTION  RemoveDirectory( VAR Directory : directorytype ) : boolean;
  301.    TYPE
  302.       registertype  =  RECORD
  303.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  304.                        END;
  305.    VAR
  306.       Registers  :  registertype;
  307.  
  308.    BEGIN
  309.    WITH Registers DO
  310.       BEGIN
  311.       AX := $3A shl 8;
  312.       DS := Seg( Directory );
  313.       DX := Ofs( Directory ) +1;
  314.       MSDOS( Registers );
  315.       IF AX = 5 THEN
  316.          BEGIN
  317.          RemoveDirectory := false;
  318.          writeln( 'Remove Directory Failed - Bad or Non-empty Directory Path' );
  319.          END
  320.       ELSE
  321.          RemoveDirectory := true;
  322.       END;  {  With  }
  323.    END;  {  **  Function RemoveDirectory **  }
  324. {.pa}
  325.  
  326.  
  327. PROCEDURE  GetAttrib(      PathName   :  path;      {  full path name  }
  328.                        VAR Attribute  :  integer );
  329.  
  330.    TYPE
  331.       registertype  =  RECORD
  332.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  333.                        END;
  334.  
  335.    VAR
  336.       Registers  :  registertype;
  337.  
  338.    BEGIN
  339.    WITH Registers DO
  340.       BEGIN
  341.       AX := $43 shl 8 + 0;
  342.       DS := Seg( PathName );
  343.       DX := Ofs( PathName ) + 1;
  344.       MSDOS( Registers );
  345.       Attribute := CX;
  346.       END;  {  With  }
  347.    END;  {  **  Procedure GetAttrib  **  }
  348.  
  349. {  Attribute byte values:
  350.                            0  -  normal read/write
  351.                            1  -  read only
  352.                            2  -  hidden
  353.                            4  -  system file
  354.                            8  -  volume label entry
  355.                           16  -  directory entry
  356.                           32  -  bit = 0 - file has not been changed,
  357.                                      = 1 - file changed, needs to be archived}
  358.  
  359.  
  360. PROCEDURE  SetAttrib(  PathName   :  path;      {  full path name  }
  361.                        Attribute  :  integer );
  362.  
  363.    TYPE
  364.       registertype  =  RECORD
  365.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  366.                        END;
  367.  
  368.    VAR
  369.       Registers  :  registertype;
  370.  
  371.    BEGIN
  372.    WITH Registers DO
  373.       BEGIN
  374.       AX := $43 shl 8 + 1;
  375.       DS := Seg( PathName );
  376.       DX := Ofs( PathName ) + 1;
  377.       CX := Attribute;
  378.       MSDOS( Registers );
  379.       IF AX = 3 THEN
  380.          writeln( AX, ' Path Not Found or Attribute Already Set' );
  381.       IF AX = 5 THEN
  382.          writeln( AX, ' Access Denied for File Type' );
  383.       END;  {  With  }
  384.    END;  {  **  Procedure SetAttrib  **  }
  385. {.pa}
  386.  
  387.  
  388. FUNCTION   GetDriveSpace(     Drive       : integer;
  389.                           VAR TotalSpace,
  390.                               FreeSpace   : real      ) : boolean;
  391.  
  392.    TYPE
  393.       registertype  =  RECORD
  394.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  395.                        END;
  396.  
  397.    VAR
  398.       Registers          :  registertype;
  399.       TotalClusters,
  400.       FreeClusters,
  401.       SectorsPerCluster,
  402.       BytesPerSector     :  real;
  403.  
  404.    BEGIN
  405.    WITH Registers DO
  406.       BEGIN
  407.       AX := $36 shl 8;
  408.       DX := Drive;
  409.       MSDOS( Registers );
  410.       IF AX = $FFFF THEN
  411.          BEGIN
  412.          GetDriveSpace := false;
  413.          writeln( 'Invalid Drive Designator' );
  414.          END
  415.       ELSE
  416.          BEGIN
  417.          GetDriveSpace := true;
  418.          TotalClusters := DX;
  419.          FreeClusters := BX;
  420.          SectorsPerCluster := AX;
  421.          BytesPerSector := CX;
  422.          TotalSpace := TotalClusters * SectorsPerCluster * BytesPerSector;
  423.          FreeSpace := FreeClusters * SectorsPerCluster * BytesPerSector;
  424.          END;
  425.       END;  {  With  }
  426.    END;  {  **  Function GetDriveSpace  **  }
  427. {.pa}
  428.  
  429.  
  430. PROCEDURE  GetDirEntry( VAR SearchName  :  name;
  431.                         VAR DirEntry    :  directoryinfo;
  432.                         VAR DirFlag     :  boolean        );
  433.  
  434.  
  435. {  Passes the next directory entry back to the calling routine.  IF DirFlag is
  436.    false Directory will get the first directory entry, if it is true Directory
  437.    will get the next directory entry.  If there are no more directory entries,
  438.    Directory will set the value of DirFlag to false.  Thus,  DirFlag  must  be
  439.    set when calling Directory, and you must check DirFlag upon returning. }
  440.  
  441.    TYPE
  442.       registertype  =  RECORD
  443.                        AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  444.                        END;
  445.       memoryaddress  =  ( segment, offset );
  446.       address        =  ARRAY[ memoryaddress ] OF integer;
  447.  
  448.  
  449.    VAR
  450.      registers  :  registertype;
  451.  
  452.  
  453.    PROCEDURE  GetDTA( VAR DTA : address );
  454.    {  get  the  Disk  Transfer  Address  where  DOS  will return the directory
  455.       information. }
  456.  
  457.       TYPE
  458.          registertype  =  RECORD
  459.                           AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : integer;
  460.                           END;
  461.  
  462.       VAR
  463.          Registers  :  registertype;
  464.  
  465.       BEGIN
  466.       WITH Registers DO
  467.          BEGIN
  468.          AX := $2F shl 8;          {Get DTA Address}
  469.          MSDOS( Registers );
  470.          DTA[ segment ] := ES;
  471.          DTA[ offset ] := BX;
  472.          END;
  473. (* no work!      for i:= 0 to 42 do MemW[DTAseg:DTAofs+i]:=0;   {clear out DTA}*)
  474.       END;  {  **  Procedure GetDTA  **  }
  475. {.pa}
  476.  
  477.  
  478.    PROCEDURE  GetEntryFromDTA( VAR DirEntry : directoryinfo );
  479.  
  480.    { GetEntry gets the directory info from the Disk Transfer Area in memory as
  481.       follows:
  482.  
  483.           DTA address +        Contents
  484.               21                 attribute
  485.               22-23              creation time
  486.               24-25              creation date
  487.               26-27              low bytes file size
  488.               28-29              high bytes file size
  489.               30-42              filename, upto 13 bytes terminated by chr(0)
  490.  
  491.    }
  492.  
  493.       VAR
  494.          registers       :  registertype;
  495.          DTA             :  address;
  496.          DTAseg,
  497.          DTAofs,
  498.          I,
  499.          Temp,
  500.          Temp1, Temp2,
  501.          Temp3           :  integer;
  502.          Hour, Min, Sec,
  503.          Month, Day      :  string[ 2 ];
  504.          Year            :  string[ 4 ];
  505.  
  506.       BEGIN
  507.          GetDTA( DTA );
  508.          DTAseg := DTA[ segment ];
  509.          DTAofs := DTA[ offset ];
  510.  
  511.          WITH DirEntry DO
  512.             BEGIN
  513.                                                    {  get the attribute byte  }
  514.             attribute := '.......';
  515.             Temp := Mem[ DTAseg : DTAofs + 21 ];
  516.             IF ( Temp AND 223 ) = 0 THEN
  517.             attribute := 'RW.....';                { regular Read/Write }
  518.             IF ( Temp AND 1 ) = 1 THEN
  519.                Insert( 'R', attribute, 1 );           { Read only file }
  520.             IF ( Temp AND 2 ) = 2 THEN
  521.                Insert( 'H', attribute, 3 );           { Hidden file }
  522.             IF ( Temp AND 4 ) = 4 THEN
  523.                Insert( 'S', attribute, 4 );           { System file }
  524.             IF ( Temp AND 8 ) = 8 THEN
  525.                Insert( 'V', attribute, 5 );           { root Volume label }
  526.             IF ( Temp AND 16 ) = 16 THEN
  527.                Insert( 'D', attribute, 6 );           { subDirectory }
  528.             IF ( Temp AND 32 ) = 32 THEN              {was '=0'}
  529.                Insert( 'A', attribute, 7 );           { Archived }
  530. {.pa}
  531. {revised time calcn by SD 7/19/85}               {  get the creation time  }
  532. {NOTE: ref Norton Prog. Guide, pg 118 -
  533.   Time = Hour*2048 + Min*32 + Sec*2 }
  534.             Temp := Mem[ DTAseg : DTAofs + 22 ];   {LSB}
  535.             Temp1 := Mem[DTAseg:DTAofs + 23];      {MSB}
  536. {            writeln('TIME 1st byte=',Temp,'/2nd byte=',Temp1);}
  537. {Min}       Temp2:= Temp shr 5 + 8*(Temp1 AND 7);  {lsb/32 + lower 3 bits of msb}
  538.             str(Temp2,Min);
  539. {Hr}        Temp3:= Temp1 shr 3;    {msb/8 vice *256/2048}
  540. {            writeln('TIME: Temp=',Temp,'/Temp1=',Temp1,'/Temp2=',Temp2,'/Temp3=',Temp3);}
  541.             Str(Temp3,Hour);
  542.  
  543.           (*original version-incorrect; off by 32 mins
  544.             str( ( Temp shr 3 ):2, Hour );
  545.             Temp := 8 * ( Temp AND 3 );
  546.             Temp := Temp + ( Mem[ DTAseg : DTAofs + 22 ] shr 5 );
  547.             str( Temp, Min );
  548.             Temp := Mem[ DTAseg : DTAofs + 22 ];
  549.             str( ( ( Temp AND 31 ) * 2 ):2, Sec ); *)
  550.  
  551.             IF Length( Min ) < 2 THEN
  552.                Min := '0' + Min;
  553.             time := Hour + ':' + Min;           { who cares about seconds? }
  554.  
  555.             {  get the creation date }
  556.             Temp := Mem[ DTAseg : DTAofs + 25 ];    {was 25}
  557.             str( ( 80 + ( Temp shr 1 ) ):2, Year );
  558.             Temp := 8 * ( Temp AND 1 );
  559.             Temp := Temp + ( Mem[ DTAseg : DTAofs + 24 ] shr 5 );
  560.             str( Temp:2, Month );
  561.             Temp := Mem[ DTAseg : DTAofs + 24 ];
  562.             str( ( Temp AND 31 ), Day );
  563.             IF Length( Day ) < 2 THEN
  564.                Day := '0' + Day;
  565.             date := Month + '-' + Day + '-' + Year;
  566.  
  567.             {  get the filesize }
  568.             size := 0;
  569.             size := Mem[ DTAseg : DTAofs + 26 ];
  570.             size := size + Mem[ DTAseg : DTAofs + 27 ] * 256.0;
  571.             size := size + Mem[ DTAseg : DTAofs + 28 ] * 256.0 * 256.0;
  572.             size := size + Mem[ DTAseg : DTAofs + 29 ] * 256.0 * 256.0 *256.0;
  573.  
  574.             {  get the filename and store in DirEntry  }
  575.             filename := '';
  576.             I := 30;
  577.             Temp := Mem[ DTAseg : DTAofs + I ];
  578.             WHILE ( I <= 41 ) AND ( Temp <> 0 ) DO
  579.                BEGIN
  580.                filename := filename + chr( Temp );
  581.                I := I + 1;
  582.                Temp := Mem[ DTAseg : DTAofs + I ];
  583.                END;  {  While  }
  584.            END;  {  With  }
  585.       END;   {  ***  Procedure GetEntry  ***  }
  586. {.pa}
  587.  
  588.    BEGIN   {  *****  Directory Routine  *****  }
  589.  
  590.       WITH Registers DO
  591.          BEGIN
  592.          IF DirFlag = false THEN      {  get the first directory entry  }
  593.             BEGIN
  594.             DirFlag := true;
  595.             DS := Seg( SearchName );
  596.             DX := Ofs( SearchName ) + 1;
  597.             CX := 31;
  598.             AX := $4E shl 8;
  599.             MSDOS( Registers );       {Find First dir entry --> DTA}
  600.             {writeln('Find First: AX =',AX);}
  601.             IF AX = 0 THEN             {  AX returns 0 as long as there are }
  602.                GetEntryFromDTA( DirEntry )       {  more directory entries. }
  603.             ELSE
  604.                DirFlag := false;       {eg AX=18 if no files found this first time}
  605.             END
  606.          ELSE                          {  else Get the Next directory entry  }
  607.             BEGIN                      {  DOS remembers the last file        }
  608.             AX := $4F shl 8;           {  searched for.                      }
  609.             MSDOS( Registers );
  610.             {writeln('Find Next: AX =',AX);}
  611.             IF AX = 0 THEN             {  AX returns 0 as long as there are }
  612.                GetEntryFromDTA( DirEntry )       {  more directory entries. }
  613.             ELSE
  614.                DirFlag := false;       {AX=18 if no more files are found}
  615.             END;  {  Outer If  }
  616.  
  617.          END;  {  With Registers  }
  618.    END;  {  ***  Procedure  Directory  ***  }
  619.  
  620.  
  621. PROCEDURE  FormatFilename(  VAR  Filename  :  name  );
  622.  
  623. VAR
  624.    LengthName,
  625.    TrailingBlanks,
  626.    I, J             :  integer;
  627.  
  628. BEGIN
  629.    LengthName := Length( Filename );
  630.    TrailingBlanks := 12 - LengthName;
  631.    I := 1;
  632.    WHILE ( I < 9 ) AND ( I < LengthName ) DO
  633.       BEGIN
  634.       IF ( FileName[ I ] = '.' ) THEN
  635.          BEGIN
  636.          FOR J := I TO 8 DO
  637.             Insert( ' ', Filename, J );
  638.          I := 9;
  639.          END;
  640.       I := I + 1;
  641.       END;  {  While  }
  642.  
  643.    FOR I := Length( Filename ) TO 12 DO
  644.       Filename := Filename + ' ';
  645. END;  {  **  Procedure FormatFilename  **  }
  646. {.pa}
  647.  
  648.  
  649. {* SD; 10/01/85}
  650. { note: now does support drive name; does NOT support path}
  651. function GetSearchName(InStrng:name):name;
  652. var
  653.    TempName : name;
  654.    i1,i2,i3,           {counters}
  655.    imax,            {highest posn to replace with '??..'}
  656.    dotpos1,         {position of dot in filename}
  657.    dotpos2          {dot posn in default search string}
  658.    : integer;
  659.    ch : char;
  660. begin
  661.    TempName := ''; {null string}
  662.  
  663. {*TEST}
  664. (*   write('TEST input filespec: '); readln(InStrng);
  665.    i1:=length(InStrng);
  666.    {writeln('Length = ',i1);}
  667.    for i2 :=1 to i1 do InStrng[i2]:=UpCase(InStrng[i2]); *)
  668.  
  669.    if (Length(InStrng) = 0) Then
  670.    TempName := Default_SearchName     {default searches for all files}
  671.  
  672.    else      {eg 'B:'}
  673.    if (Length(InStrng)=2) and (Pos(':',InStrng) >0)  THEN
  674.    begin
  675.      TempName := Default_SearchName;
  676.      if InStrng<>DefaultDrive then ChangeDefaultDrive(InStrng);
  677.    end {if pos}
  678.  
  679.    else
  680.    begin    { want to replace 'AB?C*.?P*' with 'AB?C????.?P?'+ chr(0) }
  681.       dotpos1 := pos('.',InStrng);
  682.       dotpos2 := pos('.',Default_SearchName);
  683. {      writeln('DOT1=',dotpos1:4,'/DOT2=',dotpos2:4);}
  684.  
  685.       if dotpos1 = 0 then dotpos1 := length(InStrng) +1;
  686.       i1 := 1; i3 := 1;
  687.       repeat
  688.           {if filename prefix had no wildcards, eg abc.*}
  689.           if (i1 > dotpos1) and (i3<=dotpos2) then i3 := dotpos2 + 1;
  690.           ch := InStrng[i1];
  691. {          write('CH>',ch,'<');}
  692.           if ch <> '*' then TempName := TempName + ch  {eg 'A'}
  693.           else
  694.           begin                   {replace wild cards with ???}
  695.             i2 := i3;
  696.             if i1<=dotpos1 then imax:= dotpos2-1 else
  697.             imax:=length(Default_SearchName);
  698. {            writeln('i2=',i2:4,'/i3=',i3:4);}
  699.             while (i2 <= imax) do
  700.             begin                    {replace * with ??..}
  701.               TempName := TempName + '?';
  702. {              writeln('i2=',i2:4,'>',TempName,'<');}
  703.               i2 := i2 +1;
  704.             end; {while}
  705.             if i1<= dotpos1 then
  706.             begin
  707.               i1 := dotpos1-1;  {skip to char before the dot}
  708.               i3 := dotpos2-1;
  709.             end
  710.             else
  711.             i1 := length(InStrng);   {skip to last char}
  712.           end; {if ch}
  713.           i1 := i1 + 1;
  714.           i3 := i3 + 1;
  715.       until (i1>length(InStrng));
  716.    end; {if len instrng}
  717.  
  718.    TempName := TempName + chr(0);
  719.    GetSearchName := TempName;
  720.    writeln('Search name >',TempName,'<');
  721. end; {GetSearchName}
  722.  
  723.  
  724.  
  725.  
  726. {  **  Main routine declarations  **  }
  727.  
  728. VAR
  729.   NumberFiles    :  integer;
  730.   Attribute      :  integer;
  731.   PathName       :  path;
  732.   DriveLetter   :  drivedesignator;
  733.  
  734. {  **  end Main routine declarations  **  }
  735.  
  736. {============ delete following line to run this as a program, vice .INC file}
  737. (*
  738. var driveno: char;
  739.     OldDrive: Drivedesignator;
  740.  
  741. BEGIN  {  **  Main Routine  **  }
  742. CmdTail := CheckCommandLine;
  743.  
  744. if cmdTail='' then
  745. begin
  746.   write('Which drive (A-B-C-D) ? ');
  747.   readln(driveno);
  748.   CmdTail:= UpCase(driveno) + ':';
  749. end;
  750.  
  751. OldDrive := DefaultDrive;    {the drive the program was called from}
  752.  
  753. writeln('Command tail >',CmdTail,'<');
  754. writeln('Called from drive:',OldDrive);
  755.  
  756. SearchName := GetSearchName(CmdTail);
  757.  
  758. DriveLetter := DefaultDrive;
  759. GetCurrentDirectory( Directory );
  760. writeln('Current Directory: ', DriveLetter, Directory );
  761. writeln;
  762.  
  763. NumberFiles := 0;
  764. DirSize := 0;
  765. DirFlag := false;                  {  get the first directory entry  }
  766.  
  767. GetDirEntry( SearchName, DirEntry, DirFlag );
  768. {writeln('DIRFLAG=',DirFlag);}
  769.  
  770. if DirFlag=False then writeln('NO matching files found')
  771.  
  772. else
  773.  
  774. begin
  775.   WHILE  DirFlag = true DO
  776.      BEGIN
  777.      WITH DirEntry DO
  778.         BEGIN
  779.           FormatFilename( filename );
  780.           writeln( filename:12, size:10:0, attribute:10, date:12, time:10 );
  781.           IF attribute[ 1 ] = 'R' THEN  NumberFiles := NumberFiles + 1;
  782.           DirSize := DirSize + size;
  783.           GetDirEntry( SearchName, DirEntry, DirFlag );
  784.         END;  {  With  }
  785.   END;  {  While  }
  786. end; {if DirFlag}
  787.  
  788. {  get drive total / free space   }
  789. Drive := 0;  {  current drive  }
  790. IF GetDriveSpace( Drive, TotalSpace, FreeSpace ) THEN
  791.    BEGIN
  792.    writeln;
  793.    writeln( TotalSpace:8:0, '  Bytes Total Disk Space' );
  794.    writeln( FreeSpace:8:0,  '  Bytes Free' );
  795.    writeln( DirSize:8:0,    '  Bytes This Listing in ',
  796.             NumberFiles:3,  ' Files'                      );
  797.    END;
  798.    ChangeDefaultDrive(OldDrive);
  799. END.
  800. (**)
  801.