home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w048 / 2.ddi / MSSRC.ARC / MSDIR.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-12-21  |  17.8 KB  |  575 lines

  1. {                            MSDIR.PAS
  2.                                MS 4.0
  3.                 Copyright (c) 1985, 87 by Borland International, Inc.         }
  4.  
  5. {$I msdirect.inc}
  6.  
  7. unit MsDir;
  8.   {-Handle directory picking for MicroStar}
  9.  
  10. interface
  11.  
  12. uses
  13.   Crt,                       {Basic video operations - standard unit}
  14.   Dos,                       {DOS interface - standard unit}
  15.   Errors,                    {Runtime error handler}
  16.   MsVars,                    {Global types and declarations}
  17.   MsScrn1,                   {Fast screen writing routines}
  18.   MsString,                  {String primitives}
  19.   MsPtrOp,                   {Pointer primitives}
  20.   EscSeq,                    {Returns text string for extended scan codes}
  21.   MsCmds,                    {Maps keystrokes to commands}
  22.   Int24,                     {DOS critical error handler}
  23.   Message,                   {Message system}
  24.   MsUser,                    {User keyboard input, line edit, error report, help}
  25.   MsMemOp,                   {Text buffer allocation and deallocation}
  26.   MsBack,                    {Background processes}
  27.   MsScrn2,                   {Editor screen updating}
  28.   MsMenu;                    {Popup menus}
  29.  
  30. function EdPickdir(Mask : Filepath;
  31.                    Msgno : Integer;
  32.                    Attr : Byte;
  33.                    ReturnFile : Boolean) : Filepath;
  34.   {-Return a file name, or just browse, via a popup directory}
  35.  
  36.   {==========================================================================}
  37.  
  38. implementation
  39.  
  40. const
  41.   AbsMaxFiles = 500;         {Absolute maximum number of files displayed in a directory}
  42.  
  43. type
  44.   FileArray = array[1..AbsMaxFiles] of Filename; {Array used for sorting file directories}
  45.   FileArrayPtr = ^FileArray;
  46.  
  47. var
  48.   Fname : FileArrayPtr;      {Pointer to sorted array of filenames}
  49.   Frec : SearchRec;          {File record returned by DOS unit}
  50.  
  51.  
  52.   procedure EdWriteEntry(var W : WindowRec; Num : Integer; Row, Attr : Byte);
  53.     {-Write one directory entry to the screen}
  54.  
  55.   begin                      {EdWriteEntry}
  56.     with W do
  57.       EdFastWrite(EdPadEntry(Fname^[Num], XSize-2), YPosn+Row, Succ(XPosn), Attr);
  58.   end;                       {EdWriteEntry}
  59.  
  60.   procedure EdDrawFullPage(var W : WindowRec; Num, Lines : Integer);
  61.     {-Draw one full window full of entries, starting at entry num}
  62.   var
  63.     I : Integer;
  64.  
  65.   begin                      {EdDrawFullPage}
  66.     for I := 1 to Lines do
  67.       EdWriteEntry(W, Pred(Num+I), I, ScreenAttr[MnColor]);
  68.   end;                       {EdDrawFullPage}
  69.  
  70.   procedure EdShowUpDownArrows(var W : WindowRec; Num, MinRow, MaxRow : Integer);
  71.     {-Indicate that other entries are off ends of menu}
  72.   var
  73.     Ch : Char;
  74.  
  75.   begin                      {EdShowUpDownArrows}
  76.     with W do begin
  77.       if Num > MinRow then
  78.         {More words are above top of window}
  79.         Ch := ^X
  80.       else
  81.         Ch := Blank;
  82.       EdFastWrite(Ch, Pred(YPosn+YSize), XPosn+XSize-13, ScreenAttr[MfColor]);
  83.       if Num < MaxRow then
  84.         {More words are below bottom of window}
  85.         Ch := ^Y
  86.       else
  87.         Ch := Blank;
  88.       EdFastWrite(Ch, Pred(YPosn+YSize), XPosn+XSize-12, ScreenAttr[MfColor]);
  89.     end;
  90.   end;                       {EdShowUpDownArrows}
  91.  
  92.   function EdPickDirectory(var W : WindowRec;
  93.                            TotalFiles : Integer;
  94.                            Mask : Filepath) : Filepath;
  95.     {-Browse and return full Filepath of selected file}
  96.   var
  97.     OldNum, Num : Integer;
  98.     Row, Lines, Newrow : Byte;
  99.     Ch : Char;
  100.     Quitting : Boolean;
  101.  
  102.     function EdFullFilepath(Mask : Filepath; Fname : Filename) : Filepath;
  103.       {-Return a Filepath combining mask and fname}
  104.  
  105.     begin                    {EdFullFilepath}
  106.       {Avoid attachment of default extension}
  107.       if Pos(Period, Fname) = 0 then
  108.         Fname := Fname+Period;
  109.       if EdHasWildCards(Mask) then
  110.         {Remove trailing wildcard}
  111.         while not(EdDosPathDelim(Mask[Length(Mask)])) do
  112.           Dec(Mask[0]);
  113.       EdFullFilepath := EdAddTrailingBackslash(Mask)+Fname;
  114.     end;                     {EdFullFilepath}
  115.  
  116.     procedure EdScanFiles(MatchChar : Char; var Num : Integer);
  117.       {-Scan through the file list until the name matches or exceeds the match string}
  118.  
  119.     begin                    {EdScanFiles}
  120.       if Fname^[Num] [1] < MatchChar then
  121.         {Scan forward}
  122.         while (Num < TotalFiles) and (Fname^[Num] [1] < MatchChar) do
  123.           Inc(Num)
  124.       else if Fname^[Num] [1] > MatchChar then
  125.         {Scan backward}
  126.         while (Num > 1) and (Fname^[Num] [1] > MatchChar) do
  127.           Dec(Num);
  128.     end;                     {EdScanFiles}
  129.  
  130.   begin                      {EdPickDirectory}
  131.     with W do begin
  132.  
  133.       if TotalFiles <= 0 then begin
  134.  
  135.         {Display message and wait for <Esc>}
  136.         for Num := 1 to 3 do
  137.           EdFastWrite(EdGetMessage(30+Num), YPosn+Num, XPosn+2, ScreenAttr[MnColor]);
  138.         repeat
  139.           Ch := EdGetAnyChar;
  140.         until Abortcmd or (Ch = #27);
  141.         {Clear keyboard buffer}
  142.         EdClearBuffer;
  143.         EdPickDirectory := '';
  144.  
  145.       end else begin
  146.  
  147.         Lines := YSize-2;
  148.         Num := 1;
  149.         Row := 1;
  150.         EdDrawFullPage(W, Num, Lines);
  151.         Quitting := False;
  152.  
  153.         repeat
  154.  
  155.           {Highlight the selected entry}
  156.           EdWriteEntry(W, Num, Row, ScreenAttr[MsColor]);
  157.  
  158.           if TotalFiles > Lines then
  159.             {Indicate that other entries are off ends of menus}
  160.             EdShowUpDownArrows(W, Num, Row, TotalFiles+Row-Lines);
  161.  
  162.           Ch := EdGetCursorCommand(DirCmdSet);
  163.           case Ch of
  164.  
  165.             ^M :             {Select}
  166.               Quitting := True;
  167.  
  168.             ^[ :             {Escape}
  169.               begin
  170.                 Num := 0;
  171.                 Quitting := True;
  172.               end;
  173.  
  174.             '0'..'9', 'A'..'Z',
  175.             '!', '#'..')', '-',
  176.             '@', '^'..'`', '{',
  177.             '}', '~' :       {Scan for character}
  178.               begin
  179.                 OldNum := Num;
  180.                 EdScanFiles(Ch, Num);
  181.                 if Num <> OldNum then begin
  182.                   Newrow := Row+Num-OldNum;
  183.                   if Newrow > Lines then begin
  184.                     {Off bottom of list}
  185.                     if Lines <= (TotalFiles-Num) then begin
  186.                       Row := 1;
  187.                       EdDrawFullPage(W, Num, Lines);
  188.                     end else begin
  189.                       EdDrawFullPage(W, Succ(TotalFiles-Lines), Lines);
  190.                       Row := Lines-(TotalFiles-Num);
  191.                     end;
  192.                   end else if Newrow < 1 then begin
  193.                     {Off top of list}
  194.                     Row := 1;
  195.                     EdDrawFullPage(W, Num, Lines);
  196.                   end else begin
  197.                     {On current screen}
  198.                     EdWriteEntry(W, OldNum, Row, ScreenAttr[MnColor]);
  199.                     Row := Newrow;
  200.                   end;
  201.                 end;
  202.               end;
  203.  
  204.             ^E :             {Scroll up}
  205.               if Num > 1 then begin
  206.                 EdWriteEntry(W, Num, Row, ScreenAttr[MnColor]);
  207.                 Dec(Num);
  208.                 if Row = 1 then begin
  209.                   GoToXY(1, 1);
  210.                   InsLine;
  211.                 end else
  212.                   Dec(Row);
  213.               end else if Lines >= TotalFiles then begin
  214.                 {Wrap to end}
  215.                 Num := TotalFiles;
  216.                 Row := TotalFiles;
  217.                 EdDrawFullPage(W, Succ(Num-Row), Lines);
  218.               end;
  219.  
  220.             ^X :             {Scroll down}
  221.               if Num < TotalFiles then begin
  222.                 EdWriteEntry(W, Num, Row, ScreenAttr[MnColor]);
  223.                 Inc(Num);
  224.                 if Row >= Lines then begin
  225.                   GoToXY(1, 1);
  226.                   DelLine;
  227.                   Row := Lines;
  228.                 end else
  229.                   Inc(Row);
  230.               end else if Lines >= TotalFiles then begin
  231.                 {Wrap to begin}
  232.                 Num := 1;
  233.                 Row := 1;
  234.                 EdDrawFullPage(W, Num, Lines);
  235.               end;
  236.  
  237.             ^R :             {Page up}
  238.               if Num > 1 then begin
  239.                 if Num > Lines then
  240.                   Num := Num-Lines
  241.                 else
  242.                   Num := 1;
  243.                 Row := 1;
  244.                 EdDrawFullPage(W, Num, Lines);
  245.               end;
  246.  
  247.             ^C :             {Page down}
  248.               if Num < TotalFiles then begin
  249.                 Num := Num+Lines;
  250.                 if Num > TotalFiles then
  251.                   Num := TotalFiles;
  252.                 Row := Lines;
  253.                 EdDrawFullPage(W, Succ(Num-Row), Lines);
  254.               end;
  255.  
  256.             ^T :             {Top of list}
  257.               if Num > 1 then begin
  258.                 Num := 1;
  259.                 Row := 1;
  260.                 EdDrawFullPage(W, Num, Lines);
  261.               end;
  262.  
  263.             ^B :             {Bottom of list}
  264.               if Num < TotalFiles then begin
  265.                 Num := TotalFiles;
  266.                 Row := Lines;
  267.                 EdDrawFullPage(W, Succ(Num-Row), Lines);
  268.               end;
  269.  
  270.           end;
  271.         until Abortcmd or Quitting;
  272.  
  273.         if Abortcmd or (Num = 0) then
  274.           EdPickDirectory := ''
  275.         else
  276.           EdPickDirectory := EdFullFilepath(Mask, Fname^[Num]);
  277.  
  278.       end;
  279.     end;
  280.   end;                       {EdPickDirectory}
  281.  
  282.   procedure EdBrowseDirectory(var W : WindowRec;
  283.                               TotalFiles : Integer);
  284.     {-Browse file directory}
  285.   var
  286.     LastNum, Num : Integer;
  287.     Lines : Byte;
  288.     Ch : Char;
  289.     Quitting : Boolean;
  290.  
  291.   begin                      {EdBrowseDirectory}
  292.     with W do begin
  293.  
  294.       if TotalFiles <= 0 then begin
  295.  
  296.         for Num := 1 to 3 do
  297.           EdFastWrite(EdGetMessage(30+Num), YPosn+Num, XPosn+2, ScreenAttr[MnColor]);
  298.         repeat
  299.           Ch := EdGetAnyChar;
  300.         until Abortcmd or (Ch = #27);
  301.         EdClearBuffer;
  302.  
  303.       end else begin
  304.  
  305.         Lines := YSize-2;
  306.         Num := 1;
  307.         LastNum := Succ(TotalFiles-Lines);
  308.         EdDrawFullPage(W, Num, Lines);
  309.         Quitting := False;
  310.  
  311.         repeat
  312.  
  313.           if TotalFiles > Lines then
  314.             {Indicate that other entries are off ends of menu}
  315.             EdShowUpDownArrows(W, Num, 1, LastNum);
  316.  
  317.           case EdGetCursorCommand(DirCmdSet) of
  318.  
  319.             ^M, ^[ :         {Select, Escape}
  320.               Quitting := True;
  321.  
  322.             ^E :             {Scroll up}
  323.               if Num > 1 then begin
  324.                 Dec(Num);
  325.                 GoToXY(1, 1);
  326.                 InsLine;
  327.                 EdWriteEntry(W, Num, 1, ScreenAttr[MnColor]);
  328.               end;
  329.  
  330.             ^X :             {Scroll down}
  331.               if Num < LastNum then begin
  332.                 Inc(Num);
  333.                 GoToXY(1, 1);
  334.                 DelLine;
  335.                 EdWriteEntry(W, Pred(Num+Lines), Lines, ScreenAttr[MnColor]);
  336.               end;
  337.  
  338.             ^R :             {Page up}
  339.               if Num > 1 then begin
  340.                 if Num > Lines then
  341.                   Num := Num-Lines
  342.                 else
  343.                   Num := 1;
  344.                 EdDrawFullPage(W, Num, Lines);
  345.               end;
  346.  
  347.             ^C :             {Page down}
  348.               if Num < LastNum then begin
  349.                 Num := Num+Lines;
  350.                 if Num > LastNum then
  351.                   Num := LastNum;
  352.                 EdDrawFullPage(W, Num, Lines);
  353.               end;
  354.  
  355.             ^T :             {Top of list}
  356.               if Num > 1 then begin
  357.                 Num := 1;
  358.                 EdDrawFullPage(W, Num, Lines);
  359.               end;
  360.  
  361.             ^B :             {Bottom of list}
  362.               if Num < LastNum then begin
  363.                 Num := LastNum;
  364.                 EdDrawFullPage(W, Num, Lines);
  365.               end;
  366.  
  367.           end;
  368.         until Abortcmd or Quitting;
  369.  
  370.       end;
  371.     end;
  372.   end;                       {EdBrowseDirectory}
  373.  
  374.   function EdPickdir(Mask : Filepath;
  375.                      Msgno : Integer;
  376.                      Attr : Byte;
  377.                      ReturnFile : Boolean) : Filepath;
  378.     {-Return a file name, or just browse, via a popup directory}
  379.   label
  380.     ExitPoint;
  381.   const
  382.     FilesPerPage = 17;
  383.   var
  384.     MaxFiles, TotalFiles : Integer;
  385.     Wid, Len : Byte;
  386.     UsePopup : Boolean;
  387.     Title : VarString;
  388.     W : WindowRec;
  389.  
  390.     function EdGetFileOK(GetFirst : Boolean;
  391.                          Mask : Filepath;
  392.                          Attr : Byte;
  393.                          var TotalFiles : Integer) : Boolean;
  394.       {-Read entry in DOS directory}
  395.  
  396.     begin                    {EdGetFileOK}
  397.  
  398.       {Call the DOS unit to get the directory entry}
  399.       if GetFirst then
  400.         findfirst(Mask, Attr, Frec)
  401.       else
  402.         findnext(Frec);
  403.  
  404.       if hi(EdINT24Result) <> 0 then begin
  405.         {DOS critical error}
  406.         EdGetFileOK := False;
  407.         TotalFiles := 0;
  408.         EdErrormsg(128);
  409.       end else if (doserror <> 0) or (TotalFiles >= MaxFiles) then
  410.         {No more files}
  411.         EdGetFileOK := False
  412.       else begin
  413.         {Filter directories vs. normal files}
  414.         if (Frec.Attr and 16) = (Attr and 16) then begin
  415.           Inc(TotalFiles);
  416.           Fname^[TotalFiles] := Frec.name;
  417.         end;
  418.         EdGetFileOK := True;
  419.       end;
  420.     end;                     {EdGetFileOK}
  421.  
  422.     procedure EdGetDirectory(Mask : Filepath;
  423.                              Attr : Byte;
  424.                              var TotalFiles : Integer);
  425.       {-Return a sorted array filled with files matching mask}
  426.  
  427.       procedure EdSortDirectory(TotalFiles : Integer);
  428.         {-Shellsort the directory entries}
  429.       var
  430.         Offset, I, J, K : Integer;
  431.         InOrder : Boolean;
  432.         Tmp : Filename;
  433.  
  434.         function EdSortKeyLess(var F1, F2 : Filename) : Boolean;
  435.           {-Compare the sort keys for f1 and f2}
  436.           {Replace function for other sort orders}
  437.  
  438.         begin                {EdSortkeyLess}
  439.           EdSortKeyLess := (F1 < F2);
  440.         end;                 {EdSortKeyLess}
  441.  
  442.       begin                  {EdSortDirectory}
  443.         Offset := TotalFiles;
  444.         while Offset > 1 do begin
  445.           Offset := Offset shr 1;
  446.           repeat
  447.             InOrder := True;
  448.             K := TotalFiles-Offset;
  449.             for J := 1 to K do begin
  450.               I := J+Offset;
  451.               if EdSortKeyLess(Fname^[I], Fname^[J]) then begin
  452.                 {Swap names}
  453.                 Tmp := Fname^[J];
  454.                 Fname^[J] := Fname^[I];
  455.                 Fname^[I] := Tmp;
  456.                 InOrder := False;
  457.               end;
  458.             end;
  459.           until InOrder;
  460.         end;
  461.       end;                   {EdSortDirectory}
  462.  
  463.     begin                    {EdGetDirectory}
  464.  
  465.       {Initialize}
  466.       TotalFiles := 0;
  467.  
  468.       {Read the directory}
  469.       if EdGetFileOK(True, Mask, Attr, TotalFiles) then
  470.         repeat
  471.         until not(EdGetFileOK(False, Mask, Attr, TotalFiles));
  472.  
  473.       {Sort the directory}
  474.       if TotalFiles > 0 then
  475.         EdSortDirectory(TotalFiles);
  476.  
  477.     end;                     {EdGetDirectory}
  478.  
  479.   begin                      {EdPickDir}
  480.  
  481.     EdPickdir := '';
  482.  
  483.     {Allocate space for array of files, as many as will fit}
  484.     if MaxAvail > AbsMaxFiles*SizeOf(Filename) then
  485.       MaxFiles := AbsMaxFiles
  486.     else begin
  487.       MaxFiles := MaxAvail div SizeOf(Filename);
  488.       if MaxFiles < 2 then begin
  489.         EdErrormsg(35);
  490.         Exit;
  491.       end;
  492.     end;
  493.     if EdMemAvail(MaxFiles*SizeOf(Filename), FreeListTemp) then
  494.       GetMem(Fname, MaxFiles*SizeOf(Filename))
  495.     else begin
  496.       EdErrormsg(35);
  497.       Exit;
  498.     end;
  499.  
  500.     {See if popup display is required}
  501.     UsePopup := (Length(Mask) = 0) or EdHasWildCards(Mask);
  502.  
  503.     if (Attr = 0) and not(UsePopup) then begin
  504.       {See if a subdirectory name is specified}
  505.       TotalFiles := 0;
  506.       if EdGetFileOK(True, EdAddTrailingBackslash(Mask)+'*.*', 0, TotalFiles) then begin
  507.         Mask := EdAddTrailingBackslash(Mask);
  508.         UsePopup := True;
  509.       end;
  510.       if Goterror then
  511.         goto ExitPoint;
  512.     end;
  513.  
  514.     if not(ReturnFile) or UsePopup then begin
  515.  
  516.       {Prompt to use the pick function}
  517.       EdEraseMenuHelp;
  518.       EdWritePromptLine(EdGetMessage(Msgno));
  519.  
  520.       {Add default wildcard}
  521.       if EdDosPathDelim(Mask[Length(Mask)]) then
  522.         Mask := Mask+'*.*';
  523.  
  524.       {Read directory}
  525.       EdGetDirectory(Mask, Attr, TotalFiles);
  526.       if Goterror then
  527.         goto ExitPoint;
  528.  
  529.       {Set up a new window for the directory display}
  530.       Title := Blank+Mask+Blank;
  531.       Wid := Length(Title)+2;
  532.       if Wid < 16 then
  533.         Wid := 16;
  534.       if TotalFiles <= 0 then
  535.         Len := 3
  536.       else if TotalFiles < FilesPerPage then
  537.         Len := TotalFiles
  538.       else
  539.         Len := FilesPerPage;
  540.       EdSaveTextWindow(Border, Title, 20, 6, 20+Wid, 7+Len, W);
  541.  
  542.       if TotalFiles > FilesPerPage then
  543.         {Indicate that more files are available}
  544.         with W do begin
  545.           Title := EdGetMessage(263);
  546.           EdFastWrite(Title, Pred(YPosn+YSize), XPosn+XSize-14, ScreenAttr[MfColor]);
  547.         end;
  548.  
  549.       if ReturnFile then
  550.         {Browse directory and return the selected file name}
  551.         EdPickdir := EdPickDirectory(W, TotalFiles, Mask)
  552.       else begin
  553.         {Scroll through the directory}
  554.         EdPickdir := '';
  555.         EdBrowseDirectory(W, TotalFiles);
  556.       end;
  557.  
  558.       {Restore screen}
  559.       EdRestoreTextWindow(W);
  560.       if EdPtrIsNil(CurrMenu) then
  561.         EdShowMenuHelp;
  562.       EdZapPromptLine;
  563.  
  564.     end else
  565.       {Return the input filename}
  566.       EdPickdir := Mask;
  567.  
  568. ExitPoint:
  569.     {Deallocate space for array of files}
  570.     FreeMem(Fname, MaxFiles*SizeOf(Filename));
  571.  
  572.   end;                       {EdPickDir}
  573.  
  574. end.
  575.