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

  1. {                            MSFIND.PAS
  2.                                MS 4.0
  3.                 Copyright (c) 1985, 87 by Borland International, Inc.         }
  4.  
  5. {$I msdirect.inc}
  6.  
  7. unit MsFind;
  8.   {-Find and replace routines}
  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,                   {Primitive pointer operations}
  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 editing and error reporting}
  25.   MsMemOp,                   {Text buffer allocation and deallocation}
  26.   MsBack,                    {Background processes}
  27.   MsScrn2,                   {Editor screen updating}
  28.   MsEdit;                    {Basic editing commands}
  29.  
  30. var
  31.   SearchStr : VarString;     {Used by EditFind, EditFindReplace}
  32.   ReplaceStr : VarString;    {Used by EditFindReplace}
  33.   OptionStr : VarString;     {Used by EditFindReplace}
  34.   Findupper : Boolean;       {Flags controlling search operations}
  35.   Findbackward : Boolean;    {"}
  36.   Findwholeword : Boolean;   {"}
  37.   Preview : Boolean;         {"}
  38.   Global : Boolean;          {"}
  39.   Blockfind : Boolean;       {"}
  40.   FindCount : Integer;       {Number of times to apply find/replace}
  41.  
  42. function EdScanpattern(Q : PlineDesc; Pattern : VarString;
  43.                        var C : Integer) : PlineDesc;
  44.   {-Scan for pattern, returning plinedesc and column pos if found}
  45.  
  46. procedure EdGetSearchString(Xp, Yp, Width, Maxlen : Integer;
  47.                             HaveWindow : Boolean;
  48.                             var SearchStr : VarString);
  49.   {-Prompt for and return search string}
  50.  
  51. procedure EdGetOptions(Xp, Yp, Width, Maxlen : Integer;
  52.                        HaveWindow : Boolean);
  53.   {-Get search options for Find and Replace}
  54.  
  55. procedure EdGlobalInit;
  56.   {-Position cursor for a global search}
  57.  
  58. procedure EdBlockInit;
  59.   {-Position cursor for a block search}
  60.  
  61. function EdSetStartCol(Colno : Integer) : Integer;
  62.   {-Set cursor to appropriate starting position}
  63.  
  64. procedure EdFind;
  65.   {-Process find pattern command}
  66.  
  67.   {==========================================================================}
  68.  
  69. implementation
  70.  
  71.   function EdScanpattern(Q : PlineDesc; Pattern : VarString;
  72.                          var C : Integer) : PlineDesc;
  73.     {-Scan for pattern, returning plinedesc and column pos if found}
  74.   var
  75.     Lcol, Mcol, Rcol, Plen, Qlen : Integer;
  76.     Leftedge, RightEdge, Done, DidLast : Boolean;
  77.  
  78.   begin                      {EdScanpattern}
  79.  
  80.     {Initialize in case we abort out of here}
  81.     EdScanpattern := nil;
  82.  
  83.     Mcol := 0;
  84.     Plen := Length(Pattern);
  85.     DidLast := False;
  86.  
  87.     if Findupper then
  88.       EdLongUpcase(Pattern, Plen);
  89.  
  90.     while EdPtrNotNil(Q) and (Mcol = 0) do begin
  91.  
  92.       {Allow abort - check once per line}
  93.       EdBreathe;
  94.       if Abortcmd then
  95.         Exit;
  96.  
  97.       Qlen := EdTextLength(Q)+2;
  98.  
  99.       {Assure reasonable column position passed in}
  100.       if (C >= 1) and (C <= Qlen) then begin
  101.  
  102.         {Move text into a buffer which we can uppercase}
  103.         Move(Q^.Txt^[1], WorkBuf[1], Qlen);
  104.         if Findupper then
  105.           EdLongUpcase(WorkBuf, Qlen);
  106.  
  107.         if EdPtrNotNil(Q^.Fwdlink) then
  108.           {Add an EOL mark to allow searching for that}
  109.           Move(EolMark[1], WorkBuf[Pred(Qlen)], 2);
  110.  
  111.         if Findwholeword then begin
  112.  
  113.           {Special case, separate from other for speed}
  114.  
  115.           repeat
  116.  
  117.             if Qlen = 0 then
  118.               Mcol := 0
  119.             else if Findbackward then
  120.               Mcol := EdLongPosBack(WorkBuf, C, Pattern)
  121.             else
  122.               Mcol := EdLongPosFwd(WorkBuf, C, Qlen, Pattern);
  123.  
  124.             if Mcol <> 0 then begin
  125.               {Found a pattern match, see if a word}
  126.               Lcol := Pred(Mcol);
  127.               Leftedge := (Mcol = 1) or (Pos(WorkBuf[Lcol], WordDelimiters) <> 0);
  128.               Rcol := Mcol+Plen;
  129.               RightEdge := (Rcol > Qlen) or (Pos(WorkBuf[Rcol], WordDelimiters) <> 0);
  130.               if not(Leftedge and RightEdge) then begin
  131.                 {Pattern match not a whole word}
  132.                 if Findbackward then begin
  133.                   C := Rcol-2;
  134.                   Done := (C < Plen);
  135.                 end else begin
  136.                   C := Succ(Mcol);
  137.                   Done := (C+Plen > Qlen);
  138.                 end;
  139.                 Mcol := 0;
  140.               end;
  141.             end else
  142.               {No pattern match, this line is hopeless}
  143.               Done := True;
  144.  
  145.           until (Mcol <> 0) or Done;
  146.  
  147.         end else begin
  148.  
  149.           {Search the line once for the pattern}
  150.           {Mcol holds the position of the match, or 0 if not found}
  151.           if Qlen = 0 then
  152.             Mcol := 0
  153.           else if Findbackward then
  154.             Mcol := EdLongPosBack(WorkBuf, C, Pattern)
  155.           else
  156.             Mcol := EdLongPosFwd(WorkBuf, C, Qlen, Pattern);
  157.  
  158.         end;
  159.  
  160.       end;                   {start col in text part of line}
  161.  
  162.       if (Mcol = 0) then begin
  163.  
  164.         {No match - try next line}
  165.         if Blockfind then
  166.           if DidLast then
  167.             {Exit with no match}
  168.             Exit;
  169.  
  170.         {Move to next line}
  171.         if Findbackward then begin
  172.           EdBackPtr(Q);
  173.           C := EdTextLength(Q)+2;
  174.         end else begin
  175.           EdFwdPtr(Q);
  176.           C := 1;
  177.         end;
  178.  
  179.         {See if last line of block}
  180.         if Blockfind then
  181.           if Findbackward then begin
  182.             if Q = Blockfrom.Line then
  183.               DidLast := True;
  184.           end else begin
  185.             if Q = Blockto.Line then
  186.               DidLast := True;
  187.           end;
  188.       end;
  189.     end;                     {While not(matched)}
  190.  
  191.     if Mcol <> 0 then begin
  192.       {Return the line pointer and the column}
  193.       if Blockfind then
  194.         if not(EdCursorInBlock(Q, Mcol, False {True} )) then
  195.           {Cursor moved outside of block on last line}
  196.           Exit;
  197.       EdScanpattern := Q;
  198.       C := Mcol;
  199.     end;
  200.  
  201.   end;                       {EdScanpattern}
  202.  
  203.   procedure EdGetSearchString(Xp, Yp, Width, Maxlen : Integer;
  204.                               HaveWindow : Boolean;
  205.                               var SearchStr : VarString);
  206.     {-Prompt for and return search string}
  207.   var
  208.     St : VarString;
  209.  
  210.   begin                      {EdGetSearchString}
  211.     {Set default search string}
  212.     St := SearchStr;
  213.     EdAskforEditor(Xp, Yp, Width, Maxlen, HaveWindow, St);
  214.     if not(Abortcmd) then
  215.       {Save search string for next time}
  216.       SearchStr := St;
  217.   end;                       {EdGetSearchString}
  218.  
  219.   procedure EdGetOptions(Xp, Yp, Width, Maxlen : Integer;
  220.                          HaveWindow : Boolean);
  221.     {-Get search options for Find and Replace}
  222.   var
  223.     OptSt : VarString;
  224.     I : Integer;
  225.  
  226.     function EdParseNumber(var OptionStr : VarString; var I : Integer) : Integer;
  227.       {-Parse the option string, returning an Word}
  228.     var
  229.       NumStr : VarString;
  230.       Num : Integer;
  231.  
  232.     begin                    {EdParseNumber}
  233.       EdClearString(NumStr);
  234.       while (OptionStr[I] in ['0'..'9']) and (I <= Length(OptionStr)) do begin
  235.         NumStr := NumStr+OptionStr[I];
  236.         Inc(I);
  237.       end;
  238.       EdString2integer(NumStr, Num);
  239.       if Goterror then begin
  240.         {Return to default}
  241.         EdParseNumber := 1;
  242.         {Skip rest of input}
  243.         I := Length(OptionStr);
  244.       end else begin
  245.         EdParseNumber := Num;
  246.         {Don't skip any characters}
  247.         Dec(I);
  248.       end;
  249.     end;                     {EdParseNumber}
  250.  
  251.   begin                      {EdGetOptions}
  252.     if PromptForInput then begin
  253.       OptSt := OptionStr;
  254.       EdAskforEditor(Xp, Yp, Width, Maxlen, HaveWindow, OptSt);
  255.       if Abortcmd then
  256.         Exit;
  257.       OptionStr := OptSt;
  258.     end;
  259.  
  260.     {Default options}
  261.     Findupper := False;
  262.     Findbackward := False;
  263.     Findwholeword := False;
  264.     Preview := True;
  265.     Global := False;
  266.     Blockfind := False;
  267.     FindCount := 1;
  268.  
  269.     I := 1;
  270.     while I <= Length(OptionStr) do begin
  271.       case Upcase(OptionStr[I]) of
  272.         'U' : Findupper := True;
  273.         'B' : Findbackward := True;
  274.         'W' : Findwholeword := True;
  275.         'N' : Preview := False;
  276.         'G' : Global := True;
  277.         'L' : Blockfind := True;
  278.         '0'..'9' : FindCount := EdParseNumber(OptionStr, I);
  279.       end;
  280.       Inc(I);
  281.     end;
  282.   end;                       {EdGetOptions}
  283.  
  284.   procedure EdGlobalInit;
  285.     {-Position cursor for a global search}
  286.  
  287.   begin                      {EdGlobalInit}
  288.     if Findbackward then
  289.       {Go to end of file}
  290.       EdWindowBottomFile
  291.     else
  292.       {Go to beginning of file}
  293.       EdWindowTopFile;
  294.   end;                       {EdGlobalInit}
  295.  
  296.   procedure EdBlockInit;
  297.     {-Position cursor for a block search}
  298.  
  299.   begin                      {EdBlockInit}
  300.     if EdNoBlock then begin
  301.       EdErrormsg(26);
  302.       Exit;
  303.     end;
  304.     if Findbackward then
  305.       EdJumpMarker(Blockto)
  306.     else
  307.       EdJumpMarker(Blockfrom);
  308.   end;                       {EdBlockInit}
  309.  
  310.   function EdSetStartCol(Colno : Integer) : Integer;
  311.     {-Set cursor to appropriate starting position}
  312.   var
  313.     C : Integer;
  314.  
  315.   begin                      {EdSetStartCol}
  316.     if Findbackward then
  317.       {Start one column prior to the current cursor}
  318.       C := Pred(Colno)
  319.     else if Global or Blockfind or not(PositionFindAtStart) then
  320.       {Start at current column}
  321.       C := Colno
  322.     else
  323.       {Start one beyond current cursor so repeated finds move on}
  324.       C := Succ(Colno);
  325.     EdSetStartCol := C;
  326.   end;                       {EdSetStartCol}
  327.  
  328.   procedure EdFind;
  329.     {-Process find pattern command}
  330.   const
  331.     Xmin = 5;
  332.     XSize = 70;
  333.     YSize = 4;
  334.   var
  335.     C, Ymin, Count : Integer;
  336.     P : PlineDesc;
  337.     M : BlockMarker;
  338.     W : WindowPtr;
  339.     Prompt : VarString;
  340.     HaveWindow, CursorState : Boolean;
  341.  
  342.     procedure RestoreScreen;
  343.       {-Get rid of the prompt window if appropriate}
  344.  
  345.     begin                    {RestoreScreen}
  346.       if HaveWindow then begin
  347.         {Remove window}
  348.         EdRestoreWindow(W, Xmin, Ymin, XSize, YSize);
  349.         {Restore cursor}
  350.         SolidCursor := CursorState;
  351.         EdSetCursorOff;
  352.         if EdPtrIsNil(CurrMenu) then begin
  353.           EdShowMenuHelp;
  354.           EdUpdateCursor;
  355.         end;
  356.       end;
  357.     end;                     {RestoreScreen}
  358.  
  359.   begin                      {EdFind}
  360.  
  361.     AbortEnable := True;
  362.  
  363.     if PromptForInput and (EditUsercommandInput = 0) then begin
  364.       {Set up a prompt box}
  365.       EdEraseMenuHelp;
  366.       EdUpdateCmdLine;
  367.       HaveWindow := True;
  368.       with Curwin^ do
  369.         Ymin := (Firstlineno+Lastlineno) shr 1;
  370.       if Ymin > 21 then
  371.         Ymin := 21;
  372.       if EdPtrNotNil(CurrMenu) then
  373.         if Ymin < 12 then
  374.           Ymin := 12;
  375.       W := EdSetupWindow(Border, Xmin, Ymin, Pred(Xmin+XSize), Pred(Ymin+YSize), NormalBox);
  376.       CursorState := SolidCursor;
  377.       SolidCursor := False;
  378.     end else
  379.       HaveWindow := False;
  380.  
  381.     if PromptForInput then begin
  382.       if HaveWindow then begin
  383.         {Display the prompt}
  384.         Prompt := EdGetMessage(323);
  385.         EdFastWrite(Prompt, Ymin, Xmin+(XSize-Length(Prompt)) shr 1, ScreenAttr[MfColor]);
  386.       end;
  387.       EdGetSearchString(Xmin, Succ(Ymin), XSize, XSize-3, HaveWindow, SearchStr);
  388.     end;
  389.     if Abortcmd or EdStringEmpty(SearchStr) then begin
  390.       RestoreScreen;
  391.       Exit;
  392.     end;
  393.  
  394.     {Last operation was a find}
  395.     LastSearchOp := Find;
  396.  
  397.     if HaveWindow then begin
  398.       {Redraw border}
  399.       EdDrawBox(Border, Xmin, Ymin, XSize, 4, NormalBox);
  400.       {Draw new prompt}
  401.       Prompt := EdGetMessage(318);
  402.       EdFastWrite(Prompt, Ymin, Xmin+(XSize-Length(Prompt)) shr 1, ScreenAttr[MfColor]);
  403.     end;
  404.  
  405.     EdGetOptions(Xmin, Ymin+2, XSize, 6, HaveWindow);
  406.     Count := FindCount;
  407.  
  408.     {Remove the prompt box}
  409.     RestoreScreen;
  410.  
  411.     if Abortcmd or Goterror then
  412.       Exit;
  413.  
  414.     if Blockfind then begin
  415.       {Search within marked block only}
  416.       EdBlockInit;
  417.       if Goterror then
  418.         Exit;
  419.     end else if Global then
  420.       EdGlobalInit;
  421.  
  422.     EdWritePromptLine(EdGetMessage(326));
  423.     ExitMenu := True;
  424.  
  425.     {Search for the pattern}
  426.     with Curwin^ do
  427.       repeat
  428.  
  429.         {Set cursor to proper start position to avoid repeated finds}
  430.         C := EdSetStartCol(Colno);
  431.  
  432.         {Do the work of the search}
  433.         P := EdScanpattern(Curline, SearchStr, C);
  434.         Dec(Count);
  435.  
  436.         if EdPtrNotNil(P) then begin
  437.  
  438.           {Move cursor to the position found}
  439.           M.Line := P;
  440.           if Findbackward or PositionFindAtStart then
  441.             M.Col := C
  442.           else
  443.             M.Col := C+Length(SearchStr);
  444.           EdJumpMarker(M);
  445.  
  446.           if Count <= 0 then
  447.             {Show the found string clearly}
  448.             EdHighlightScreen(C, Pred(C+Length(SearchStr)), ScreenAttr[BordColor], True);
  449.  
  450.         end else if Abortcmd then
  451.           Exit
  452.  
  453.         else
  454.           {Pattern not found}
  455.           EdErrormsg(38);
  456.  
  457.       until (Count <= 0) or EdPtrIsNil(P);
  458.  
  459.   end;                       {EdFind}
  460.  
  461. begin
  462.   SearchStr := '';
  463.   ReplaceStr := '';
  464.   OptionStr := '';
  465. end.
  466.