home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / LSTDIR.ZIP / LSTDIR.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1987-10-22  |  16.7 KB  |  552 lines

  1.  
  2.   { This Procedure performs a disk directory, searching for a given
  3.     File Mask, displaying them alphabetically in a window (in multiple
  4.     pages if necessary) and restoring the screen when you have either
  5.     hit return or escape (return sets the filemask to the filename
  6.     currently selected, escape returns a null string). The function
  7.     restores the screen, so it can be called from any program without
  8.     the trouble of redrawing the screen (unless you have already accessed
  9.     the second display page in your program, then you will have to change
  10.     the Screen2 variable below to point to the third or fourth screen).
  11.     It doesn't save the screen colors, so you will have to reset those
  12.     when the procedure returns. }
  13.  
  14.   { The core procedures were taken from a file I previously took down
  15.     from Compuserve.  Unfortunately the contributor didn't include his
  16.     name in the source so I cannot give full credit. }
  17.  
  18.   { I have included several routines I use frequently which others
  19.     may also find useful.  They are a DrawBox procedure and
  20.     EnableCursor and DisableCursor procedures.    DrawBox may be redundant
  21.     with your favored box routine so replace it if you wish.  It is
  22.     only called once.  The other two, I am told, can yield strange
  23.     results so you may want to stub them out.  I have tested them on
  24.     an EGA, a CGA, and an AT&T and have seen no adverse effects
  25.     so I will leave that decision up to the users.  I think disabling
  26.     the cursor makes the screen much neater.  }
  27.  
  28. TYPE  s80      = String[80];
  29.       s14      = String[14];
  30.       FilePtr     = ^FileRec;
  31.       FileRec     = record
  32.                 Name : s14;
  33.                 Next,
  34.                 Prev : FilePtr;
  35.                end;
  36.       Registers   = Record Case Integer Of
  37.                 1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
  38.                 2: (al,ah,bl,bh,cl,ch,dl,dh: Byte);
  39.                  End;
  40.       FCB_Layout  = record
  41.                 Drive            : byte;
  42.                 FileName    : Array[1..8] of char;
  43.                 FileExt     : Array[1..3] of char;
  44.                 CurBlock    : integer;
  45.                 RecSize     : integer;
  46.                 FSizeLow    : integer;
  47.                 FSizeHigh        : integer;
  48.                 CreateDate       : integer;
  49.                 CreateTime       : integer;
  50.                 Flags            : byte;
  51.                 DiskAddr1st      : integer;
  52.                 DiskAddrLst      : integer;
  53.                 LastAccess       : Array [1..3] of byte;
  54.                 NextRecord       : byte;
  55.                 RelRecLow        : integer;
  56.                 RelRecHigh       : integer;
  57.                end;
  58.  
  59. VAR TestFileName : s14;   { For testing purposes }
  60.  
  61. PROCEDURE  DrawBox (LeftX, TopY, RightX, BottomY, LinesTop, LinesLeft,
  62.               LinesRight, LinesBottom : Integer);
  63.  
  64.   TYPE     Segtype   = Array [0..1,1..2] of Char;
  65.       Crnrtype  = Array [1..2,1..2,1..2,1..2] of Char;
  66.  
  67.   CONST  Horiz    = 0;
  68.       Vert        = 1;
  69.       Top    = 1;
  70.       Left        = 1;
  71.       Bottom    = 2;
  72.       Right       = 2;
  73.       Segment   : SegType  = ((#196,#205),(#179,#186));
  74.       Corner    : CrnrType = ((((#218,#191),(#192,#217)),
  75.                       ((#213,#184),(#212,#190))),
  76.                      (((#214,#183),(#211,#189)),
  77.                       ((#201,#187),(#200,#188))));
  78.  
  79.    VAR    I : Integer;
  80.  
  81.    BEGIN
  82.      GotoXY(LeftX,TopY);
  83.      Write(Corner[LinesLeft, LinesTop, Top, Left]);
  84.      For I := (LeftX + 1) to (RightX - 1) do
  85.      Write(Segment[Horiz, LinesTop]);
  86.      Write(Corner[LinesRight, LinesTop, Top, Right]);
  87.      For I := (TopY + 1) to (BottomY - 1) do
  88.      Begin
  89.        GotoXY(LeftX,I);  Write(Segment[Vert, Linesleft]);
  90.        GotoXY(RightX,I); Write(Segment[Vert, LinesRight]);
  91.      End;
  92.      GotoXY(LeftX,BottomY);
  93.      Write(Corner[LinesLeft, LinesBottom, Bottom, Left]);
  94.      For I := (LeftX + 1) to (RightX - 1) do
  95.      Write(Segment[Horiz, LinesBottom]);
  96.      Write(Corner[LinesRight, LinesBottom, Bottom, Right]);
  97.    END; {DrawBox}
  98.  
  99. PROCEDURE EnableCursor;    { Stub out these procedures if you do not     }
  100.  var rb : registers;       { want the cursor to disappear.  This may     }
  101.  Begin                     { be especially important if you are          }
  102.   With rb do begin         { going to be distributing your program       }
  103.     ax:=$0100;             { to machines with unknown display adapters,  }
  104.     cx:=$0607;             { in which case you may have to either        }
  105.   end;                     { provide multiple versions, or write         }
  106.   Intr(16,rb);             { something to find out what kind of display  }
  107.  End;                      { you've got attached, or use a flag in the   }
  108.                            { environment.                                }
  109.  
  110. PROCEDURE DisableCursor;   { cx is set for the start and stop scan lines }
  111.  var rb : registers;       { for the cursor: Enable starts at line 6 and }
  112.  Begin                     { ends at line 7.  Disable puts both lines    }
  113.   With rb do begin         { outside of the limits - unless you have     }
  114.     ax:=$0100;             { something like an AT&T, which has more      }
  115.     cx:=$0909;             { than 10 scan lines.  Be sure that each      }
  116.   end;                     { byte is less than $10, however, or          }
  117.   Intr(16,rb);             { unpredictable results will occur. ($0F max) }
  118.  End;
  119.  
  120. PROCEDURE ListCatalog(var FileMask : s14);
  121.  
  122. Var   DirMask     : String[80];
  123.       MarkFile,
  124.       FirstFile,
  125.       CurrFile    : FilePtr;
  126.       PageOfs,
  127.       Col,
  128.       NamesInCol,
  129.       FirstEntryInCol,
  130.       TotFiles,
  131.       Error,
  132.       No,
  133.       I        : integer;
  134.       Screen1     : Array[1..80,1..25,1..2] of Integer absolute $B800:0000;
  135.       Screen2     : Array[1..80,1..25,1..2] of Integer absolute $B900:0000;
  136.       KeyStroke   : Char;
  137.       X,Y,Z         : Integer;
  138.       RegBlock    : Registers;
  139.  
  140. PROCEDURE SetDTA(MEMSeg,MEMOff:Integer;var Err:Integer );
  141.    var
  142.       DOSRegs  :   Registers;
  143.    begin
  144.       With DOSRegs do
  145.        begin
  146.       Err   := 0;           { Assume No Error }
  147.       ah := $1A;            { Function used to set the DTA }
  148.       DS := MEMSeg;         { store the parameter Segment in DS }
  149.       DX := MEMOff;         {   "    "      "     Offset in DX }
  150.       MSDos( DOSRegs );
  151.       If (Flags And 1) = 1 then
  152.         Err := al;
  153.      end;
  154.    end;
  155.  
  156. PROCEDURE GetDTA(var MEMSeg,MEMOff:Integer; var Err : Integer );
  157.    var
  158.       DOSRegs  :   Registers;
  159.    begin
  160.       With DOSRegs do
  161.        begin
  162.       ah := $2F;             { Function used to get current DTA address }
  163.       MSDos( DOSRegs );
  164.       MEMSeg := ES;          { Segment of DTA returned by DOS }
  165.       MEMOff := BX;          { Offset of DTA returned }
  166.       If (Flags and 1)=1 then
  167.         Err := al;
  168.        end;
  169.    end;
  170.  
  171. PROCEDURE GetFirstFile( Mask : s80; var NamR : s80;
  172.               MEMSeg, MEMOff : Integer; Option : Integer;
  173.               var Err : Integer );
  174.    var
  175.       DOSRegs  :   Registers;
  176.       I : Integer;
  177.    begin
  178.       With DOSRegs do
  179.      begin
  180.        Err := 0;
  181.        ah := $4E;             { Get first directory entry }
  182.        DS := Seg( Mask );     { Point to the file Mask }
  183.        DX := Ofs( Mask )+1;
  184.        CX := Option;          { Store the Option }
  185.        MSDos( DOSRegs );
  186.        If (Flags and 1)=1 then
  187.          Err := al;
  188.      end;
  189.       I := 1;
  190.       repeat
  191.      NamR[I] := Chr(mem[MEMSeg:MEMOff+29+I]);
  192.      I := I + 1;
  193.       until ( not (NamR[I-1] in [' '..'~']));
  194.       NamR[0] := Chr(I-1);
  195.    end;
  196.  
  197. PROCEDURE GetNextFile( var NamR : s80; MEMSeg, MEMOff : Integer;
  198.                Option : Integer; var Err : Integer );
  199.    var
  200.       DOSRegs  :   Registers;
  201.       I : Integer;
  202.    begin
  203.      With DOSRegs do
  204.       begin
  205.      Err := 0;
  206.      ah := $4F;            { Function used to get the next }
  207.                            { directory entry }
  208.      CX := Option;         { Set the file option }
  209.      MSDos( DOSRegs );
  210.      If (Flags and 1)=1 then
  211.        Err := al;
  212.       end;
  213.      I := 1;
  214.      repeat
  215.        NamR[ I ] := Chr( mem[ MEMSeg : MEMOff + 29 + I ] );
  216.        I := I + 1;
  217.      until ( not ( NamR[ I - 1 ] in [ ' '..'~' ] ));
  218.      NamR[ 0 ] := Chr( I - 1 );
  219.    end;
  220.  
  221. FUNCTION WildStrComp(S,A:s80):boolean;
  222.    { this function compares two strings, string A can contain '?' }
  223.    { which match anything.                          }
  224.    Var
  225.       I,J    :  Integer;
  226.       Done,
  227.       Match  :  boolean;
  228.  
  229.    begin
  230.       Match:=true;
  231.       I:=1;
  232.       J:=Length(A);
  233.       Done:=false;
  234.       If Length(A)<>Length(S) then
  235.      Match:=false
  236.       Else
  237.      begin
  238.         While Match and not Done do
  239.           begin
  240.             If ( I > J ) then Done:=true
  241.             Else
  242.             If A[I]<>'?' then
  243.             If UpCase(A[I])<>UpCase(S[I]) then
  244.               Match:=false;
  245.             If Match then
  246.            I:=I+1;
  247.           end;
  248.      end;
  249.       WildStrComp:=Match;
  250.    end;
  251.  
  252. FUNCTION FileNameScan(S:s14):s14;
  253.    var
  254.      T      : FCB_Layout;
  255.      i      : integer;
  256.      Regs : Registers;
  257.    begin
  258.       S:=S+Chr(0);
  259.       with Regs do
  260.      begin
  261.        ah:=$29;
  262.        al:=0;
  263.        DS:=Seg(S);
  264.        SI:=Ofs(S)+1;
  265.        ES:=Seg(T);
  266.        DI:=Ofs(T);
  267.      end;
  268.       with T do
  269.      begin
  270.        for i:=1 to 8 do
  271.          FileName[i]:=' ';
  272.        for i:=1 to 3 do
  273.          FileExt[i]:=' ';
  274.      end;
  275.       MsDos(Regs);
  276.       with T do
  277.      begin
  278.        for i:=1 to 8 do
  279.          S[i]:=FileName[i];
  280.        S[9]:='.';
  281.        for i:=1 to 3 do
  282.          S[9+i]:=FileExt[i];
  283.        S[0]:=Chr(12);
  284.      end;
  285.       FileNameScan:=S;
  286.    end;
  287.  
  288. PROCEDURE FileMaskScan(var S:s14);
  289.    begin
  290.       S:=FileNameScan(S);
  291.    end;
  292.  
  293. PROCEDURE SearchDir(DirMask:s80; var FileMask:s14; var Option:Integer);
  294.   Var
  295.      SaveDTASeg,
  296.      SaveDTAOfs,
  297.      FileCount,
  298.      Attr,
  299.      Error     :   Integer;
  300.      Dir       :   boolean;
  301.      DirCur,
  302.      DTABuffer,
  303.      FileName  :   s80;
  304.      FileSize,
  305.      Total     :   Real;
  306.      PrevFile,
  307.      NewFile   :   FilePtr;
  308.   begin
  309.     DirCur:=DirMask+'*.*'+Chr(0);
  310.     GetDTA(SaveDTASeg,SaveDTAOfs,Error);
  311.     SetDTA(Seg(DTABuffer),Ofs(DTABuffer),Error);
  312.     GetFirstFile(DirCur,FileName,Seg(DTABuffer),Ofs(DTABuffer),Option,Error);
  313.     Total:=0.0;
  314.     FileCount:=0;
  315.     FirstFile := Nil;
  316.  
  317.     repeat
  318.       If WildStrComp(FileNameScan(Copy(FileName,1,Length(FileName)-1)), FileMask)
  319.      and (FileName[1] <> #229) and (FileName[1] <> '.') and (Error = 0) then
  320.        begin
  321.          FileCount:=FileCount+1;
  322.          New(NewFile);
  323.          NewFile^.Name := FileName;
  324.          NewFile^.Next := Nil;
  325.          NewFile^.Prev := Nil;
  326.          If FirstFile = Nil then
  327.            begin
  328.           FirstFile := NewFile;
  329.           MarkFile := NewFile;
  330.            end
  331.           else
  332.            begin
  333.           CurrFile := FirstFile;
  334.           While (CurrFile^.Next <> Nil) and
  335.                 (CurrFile^.Name < NewFile^.Name) do
  336.                  CurrFile := CurrFile^.Next;
  337.           If CurrFile^.Name < NewFile^.Name then
  338.             begin
  339.               CurrFile^.Next := NewFile;
  340.               NewFile^.Prev := CurrFile;
  341.               NewFile^.Next := Nil;
  342.             end
  343.            else
  344.             begin
  345.               If CurrFile^.Prev <> Nil then
  346.                 begin
  347.                PrevFile := CurrFile^.Prev;
  348.                PrevFile^.Next := NewFile;
  349.                NewFile^.Prev := PrevFile;
  350.                 end
  351.                else
  352.                 begin
  353.                NewFile^.Prev := Nil;
  354.                FirstFile := NewFile;
  355.                 end;
  356.               CurrFile^.Prev := NewFile;
  357.               NewFile^.Next := CurrFile;
  358.             end;
  359.            end;
  360.        end;
  361.       GetNextFile(FileName,Seg(DTABuffer),Ofs(DTABuffer),Option,Error);
  362.     Until Error <> 0;
  363.  
  364.     SetDTA(SaveDTASeg,SaveDTAOfs,Error);
  365.     TotFiles := FileCount;
  366.   end;
  367.  
  368. PROCEDURE SaveScreen;
  369.   begin
  370.     Move(Screen1,Screen2,4000);
  371.   end;
  372.  
  373. PROCEDURE RestoreScreen;
  374.   begin
  375.     Move(Screen2,Screen1,4000);
  376.   end;
  377.  
  378. PROCEDURE Beep;
  379.   begin
  380.     Sound(440);
  381.     Delay(100);
  382.     NoSound;
  383.   end;
  384.  
  385. PROCEDURE DispFileNames(PgOffset : Integer);
  386.   begin
  387.     ClrScr;
  388.     Write('  Files for directory ',DirMask);
  389.     If TotFiles > 60+PgOffset then Write('    PgDn for More');
  390.     X := 1+PgOffset;
  391.     FirstEntryInCol := 1+PgOffset;
  392.     Col := 2;
  393.     CurrFile := FirstFile;
  394.     For i := 1 to PgOffset do
  395.       CurrFile := CurrFile^.Next;
  396.     While (X <= TotFiles) and (X <= PgOffset+60) do
  397.       begin
  398.      While (X <= FirstEntryInCol+NamesInCol-1) and (X <= TotFiles) do
  399.        begin
  400.          GotoXY(Col, X-FirstEntryInCol+3);
  401.          Write(' ',CurrFile^.Name);
  402.          CurrFile := CurrFile^.Next;
  403.          X := X + 1;
  404.        end;
  405.      FirstEntryInCol := FirstEntryInCol + NamesInCol;
  406.      Col := Col + 15;
  407.       end;
  408.     X := 1+PgOffset;
  409.     Col := 2;
  410.     FirstEntryInCol := 1+PgOffset;
  411.     CurrFile := FirstFile;
  412.     For i := 1 to PgOffset do
  413.       CurrFile := CurrFile^.Next;
  414.   end;
  415.  
  416. BEGIN      { ListCatalog PROCEDURE }
  417.   SaveScreen;
  418.   GetDir(0,DirMask);
  419.   If DirMask[Length(DirMask)] <> '\' then DirMask := DirMask + '\';
  420.   I := 16;
  421.  
  422.   FileMaskScan(FileMask);
  423.   SearchDir(DirMask,FileMask,I);
  424.  
  425.   If TotFiles <= 60 then
  426.     begin
  427.       NamesInCol := (TotFiles div 4);
  428.       If NamesInCol*4 < TotFiles then
  429.      NamesInCol := NamesInCol + 1;
  430.     end
  431.    else
  432.     NamesInCol := 15;
  433.   TextColor(White);
  434.   TextBackground(Blue);
  435.   DrawBox(8,5,71,9+NamesInCol,1,1,1,1);
  436.   Window(9,6,70,8+NamesInCol);
  437.   TextColor(Black);
  438.   TextBackground(LightGray);
  439.  
  440.   PageOfs := 0;
  441.   DispFileNames(PageOfs);
  442.   DisableCursor;
  443.   Repeat
  444.     GotoXY(Col, X-FirstEntryInCol+3);
  445.     TextColor(White);TextBackground(Blue);
  446.     Write(' ',CurrFile^.Name,'':13-Length(CurrFile^.Name));
  447.     Read(KBD,KeyStroke);
  448.     If (KeyStroke = #27) and KeyPressed then
  449.       begin
  450.      Read(KBD,KeyStroke);
  451.      GotoXY(Col, X-FirstEntryInCol+3);
  452.      TextColor(Black);TextBackground(LightGray);
  453.      Write(' ',CurrFile^.Name,'':13-Length(CurrFile^.Name));
  454.      case KeyStroke of
  455.  
  456.        #72 : begin  { Up }
  457.             If X = 1 then
  458.               Beep
  459.              else
  460.               begin
  461.                 If X = FirstEntryInCol then
  462.                begin
  463.                  FirstEntryInCol := FirstEntryInCol - NamesInCol;
  464.                  Col := Col - 15;
  465.                end;
  466.                 X := X - 1;
  467.                 CurrFile := CurrFile^.Prev;
  468.               end
  469.           end;
  470.  
  471.        #80 : begin  { Down }
  472.             If (X = TotFiles) or (X = PageOfs+60) then
  473.               Beep
  474.              else
  475.               begin
  476.                 If X = FirstEntryInCol + NamesInCol-1 then
  477.                begin
  478.                  FirstEntryInCol := FirstEntryInCol + NamesInCol;
  479.                  Col := Col + 15;
  480.                end;
  481.                 X := X + 1;
  482.                 CurrFile := CurrFile^.Next;
  483.               end;
  484.           end;
  485.  
  486.        #73 : begin  { PgUp }
  487.             If PageOfs > 0 then
  488.                begin
  489.                  PageOfs := PageOfs - 60;
  490.                  DispFileNames(PageOfs);
  491.                end
  492.               else
  493.                Beep;
  494.           end;
  495.  
  496.        #81 : begin  { PgDown }
  497.             If PageOfs < (TotFiles-60) then
  498.                begin
  499.                  PageOfs := PageOfs + 60;
  500.                  DispFileNames(PageOfs);
  501.                end
  502.               else
  503.                Beep;
  504.           end;
  505.  
  506.        #75 : begin  { Left Arrow }
  507.             If (X <= NamesInCol+PageOfs)     then
  508.               Beep
  509.              else
  510.               begin
  511.                 FirstEntryInCol := FirstEntryInCol - NamesInCol;
  512.                 Col := Col - 15;
  513.                 X := X - NamesInCol;
  514.                 For i := 1 to NamesInCol do
  515.                CurrFile := CurrFile^.Prev;
  516.               end;
  517.           end;
  518.  
  519.        #77 : begin  { Right Arrow }
  520.             If (X + NamesInCol > TotFiles) or (X + NamesInCol > PageOfs+60) then
  521.               Beep
  522.              else
  523.               begin
  524.                 FirstEntryInCol := FirstEntryInCol + NamesInCol;
  525.                 Col := Col + 15;
  526.                 X := X + NamesInCol;
  527.                 For i := 1 to NamesInCol do
  528.                CurrFile := CurrFile^.Next;
  529.               end;
  530.           end;
  531.  
  532.         else Beep
  533.  
  534.       end; { case }
  535.       end;
  536.   Until KeyStroke in [#13,#27];
  537.   EnableCursor;
  538.   Window(1,1,80,25);
  539.   RestoreScreen;
  540.   If KeyStroke = #13 then FileMask := CurrFile^.Name
  541.     else FileMask := ' ';
  542.   Mark(MarkFile);
  543.   Release(MarkFile);
  544. END;
  545.  
  546. BEGIN   { for testing purposes }
  547.   TestFileName := '*.*';
  548.   ListCatalog(TestFileName);
  549.   ClrScr;
  550.   Writeln(TestFileName);
  551. END.
  552.