home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / tptools.zip / FIRSTED.ZIP / EDFINDS.PAS < prev    next >
Pascal/Delphi Source File  |  1987-12-21  |  19KB  |  649 lines

  1. {                          EDFINDS.PAS
  2.                              ED 4.0
  3.              Copyright (c) 1985, 87 by Borland International, Inc.            }
  4.  
  5. {$I eddirect.inc}
  6.  
  7. unit EdFinds;
  8.   {-Find and replace routines for FirstEd}
  9.  
  10. interface
  11.  
  12. uses
  13.   crt,                       {Basic video operations - standard unit}
  14.   Dos,                       {DOS calls - standard unit}
  15.   Errors,                    {Runtime error handler}
  16.   EdVars,                    {Global types and declarations}
  17.   EdScrn1,                   {Fast screen writing routines}
  18.   EdString,                  {String primitives}
  19.   EdPtrOp,                   {Primitive pointer operations}
  20.   EdCmds,                    {Maps keystrokes to commands}
  21.   int24,                     {DOS critical error handler}
  22.   Message,                   {Message system}
  23.   EdUser,                    {User keyboard input, line editing and error reporting}
  24.   EdMemOp,                   {Text buffer allocation and deallocation}
  25.   EdBack,                    {Background processes}
  26.   EdScrn2,                   {Editor screen updating}
  27.   EdEdit;                    {Basic editing commands}
  28.  
  29. procedure EdFind;
  30.   {-Process find pattern command}
  31.  
  32. procedure EdFindReplace;
  33.   {-Process find pattern in text and replace command}
  34.  
  35.   {==========================================================================}
  36.  
  37. implementation
  38.  
  39. var
  40.   SearchStr : VarString;     {Used by EditFind, EditFindReplace}
  41.   ReplaceStr : VarString;    {Used by EditFindReplace}
  42.   OptionStr : VarString;     {Used by EditFindReplace}
  43.   FindUpper : Boolean;       {Flags controlling search operations}
  44.   FindBackward : Boolean;    {"}
  45.   FindWholeWord : Boolean;   {"}
  46.   Preview : Boolean;         {"}
  47.   Global : Boolean;          {"}
  48.   Blockfind : Boolean;       {"}
  49.  
  50.   function EdScanpattern(Q : PlineDesc; Pattern : VarString; var C : Integer) : PlineDesc;
  51.     {-Scan for pattern, returning plinedesc and column pos if found}
  52.   var
  53.     Lcol, Mcol, Rcol, Plen, Qlen : Integer;
  54.     LeftEdge, RightEdge, Done, DidLast : Boolean;
  55.  
  56.   begin                      {EdScanpattern}
  57.  
  58.     {Initialize in case we abort out of here}
  59.     EdScanpattern := nil;
  60.  
  61.     Mcol := 0;
  62.     Plen := Length(Pattern);
  63.     DidLast := False;
  64.  
  65.     if FindUpper then
  66.       EdLongUpcase(Pattern, Plen);
  67.  
  68.     while EdPtrNotNil(Q) and (Mcol = 0) do begin
  69.  
  70.       {Allow abort - check once per line}
  71.       EdBreathe;
  72.       if Abortcmd then
  73.         Exit;
  74.  
  75.       Qlen := EdTextLength(Q)+2;
  76.  
  77.       {Assure reasonable column position passed in}
  78.       if (C >= 1) and (C <= Qlen) then begin
  79.  
  80.         {Move text into a buffer which we can uppercase}
  81.         Move(Q^.Txt^[1], WorkBuf[1], Qlen);
  82.         if FindUpper then
  83.           EdLongUpcase(WorkBuf, Qlen);
  84.  
  85.         if EdPtrNotNil(Q^.FwdLink) then
  86.           {Add an EOL mark to allow searching for that}
  87.           Move(EolMark[1], WorkBuf[Pred(Qlen)], 2);
  88.  
  89.         if FindWholeWord then begin
  90.  
  91.           {Special case, separate from other for speed}
  92.  
  93.           repeat
  94.  
  95.             if Qlen = 0 then
  96.               Mcol := 0
  97.             else if FindBackward then
  98.               Mcol := EdLongPosBack(WorkBuf, C, Pattern)
  99.             else
  100.               Mcol := EdLongPosFwd(WorkBuf, C, Qlen, Pattern);
  101.  
  102.             if Mcol <> 0 then begin
  103.               {Found a pattern match, see if a word}
  104.               Lcol := Pred(Mcol);
  105.               LeftEdge := (Mcol = 1) or (Pos(WorkBuf[Lcol], WordDelimiters) <> 0);
  106.               Rcol := Mcol+Plen;
  107.               RightEdge := (Rcol > Qlen) or (Pos(WorkBuf[Rcol], WordDelimiters) <> 0);
  108.               if not(LeftEdge and RightEdge) then begin
  109.                 {Pattern match not a whole word}
  110.                 if FindBackward then begin
  111.                   C := Rcol-2;
  112.                   Done := (C < Plen);
  113.                 end else begin
  114.                   C := Succ(Mcol);
  115.                   Done := (C+Plen > Qlen);
  116.                 end;
  117.                 Mcol := 0;
  118.               end;
  119.             end else
  120.               {No pattern match, this line is hopeless}
  121.               Done := True;
  122.  
  123.           until (Mcol <> 0) or Done;
  124.  
  125.         end else begin
  126.  
  127.           {Search the line once for the pattern}
  128.           {Mcol holds the position of the match, or 0 if not found}
  129.           if Qlen = 0 then
  130.             Mcol := 0
  131.           else if FindBackward then
  132.             Mcol := EdLongPosBack(WorkBuf, C, Pattern)
  133.           else
  134.             Mcol := EdLongPosFwd(WorkBuf, C, Qlen, Pattern);
  135.  
  136.         end;
  137.  
  138.       end;                   {start col in text part of line}
  139.  
  140.       if (Mcol = 0) then begin
  141.  
  142.         {No match - try next line}
  143.         if Blockfind then
  144.           if DidLast then
  145.             {Exit with no match}
  146.             Exit;
  147.  
  148.         {Move to next line}
  149.         if FindBackward then begin
  150.           EdBackPtr(Q);
  151.           C := EdTextLength(Q)+2;
  152.         end else begin
  153.           EdFwdPtr(Q);
  154.           C := 1;
  155.         end;
  156.  
  157.         {See if last line of block}
  158.         if Blockfind then
  159.           if FindBackward then begin
  160.             if Q = Blockfrom.Line then
  161.               DidLast := True;
  162.           end else begin
  163.             if Q = Blockto.Line then
  164.               DidLast := True;
  165.           end;
  166.       end;
  167.     end;                     {While not(matched)}
  168.  
  169.     if Mcol <> 0 then begin
  170.       {Return the line pointer and the column}
  171.       if Blockfind then
  172.         if not(EdCursorInBlock(Q, Mcol, False {True} )) then
  173.           {Cursor moved outside of block on last line}
  174.           Exit;
  175.       EdScanpattern := Q;
  176.       C := Mcol;
  177.     end;
  178.  
  179.   end;                       {EdScanpattern}
  180.  
  181.   {*** xp has succ(promptlen), yp ignored}
  182.   procedure EdGetSearchString(Xp, Yp, Width, MaxLen : Integer;
  183.                               HaveWindow : Boolean;
  184.                               var SearchStr : VarString);
  185.     {-Prompt for and return search string}
  186.   var
  187.     St : VarString;
  188.  
  189.   begin                      {EdGetSearchString}
  190.     {Set default search string}
  191.     St := SearchStr;
  192.     EdAskforEditor(Xp, 1, Width, MaxLen, HaveWindow, St);
  193.     if not(Abortcmd) then
  194.       {Save search string for next time}
  195.       SearchStr := St;
  196.   end;                       {EdGetSearchString}
  197.  
  198.   {*** xp has succ(promptlen), yp ignored}
  199.   procedure EdGetOptions(Xp, Yp, Width, MaxLen : Integer; HaveWindow : Boolean);
  200.     {-Get search options for Find and Replace}
  201.   var
  202.     OptSt : VarString;
  203.     I : Integer;
  204.  
  205.   begin                      {EdGetOptions}
  206.     if PromptForInput then begin
  207.       OptSt := OptionStr;
  208.       EdAskforEditor(Xp, 1, Width, MaxLen, HaveWindow, OptSt);
  209.       if Abortcmd then
  210.         Exit;
  211.       OptionStr := OptSt;
  212.     end;
  213.     FindUpper := False;
  214.     FindBackward := False;
  215.     FindWholeWord := False;
  216.     Preview := True;
  217.     Global := False;
  218.     Blockfind := False;
  219.     for I := 1 to Length(OptionStr) do
  220.       case Upcase(OptionStr[I]) of
  221.         'U' : FindUpper := True;
  222.         'B' : FindBackward := True;
  223.         'W' : FindWholeWord := True;
  224.         'N' : Preview := False;
  225.         'G' : Global := True;
  226.         'L' : Blockfind := True;
  227.       end;
  228.   end;                       {EdGetOptions}
  229.  
  230.   procedure EdGlobalInit;
  231.     {-Position cursor for a global search}
  232.  
  233.   begin                      {EdGlobalInit}
  234.     if FindBackward then
  235.       {Go to end of file}
  236.       EdWindowBottomFile
  237.     else
  238.       {Go to beginning of file}
  239.       EdWindowTopFile;
  240.   end;                       {EdGlobalInit}
  241.  
  242.   procedure EdBlockInit;
  243.     {-Position cursor for a block search}
  244.  
  245.   begin                      {EdBlockInit}
  246.     if EdNoBlock then begin
  247.       EdErrormsg(26);
  248.       Exit;
  249.     end;
  250.     if FindBackward then
  251.       EdJumpMarker(Blockto)
  252.     else
  253.       EdJumpMarker(Blockfrom);
  254.   end;                       {EdBlockInit}
  255.  
  256.   function EdSetStartCol(ColNo : Integer) : Integer;
  257.     {-Set cursor to appropriate starting position}
  258.   var
  259.     C : Integer;
  260.  
  261.   begin                      {EdSetStartCol}
  262.     if FindBackward then
  263.       {Start one column prior to the current cursor}
  264.       C := Pred(ColNo)
  265.     else if Global or Blockfind or not(PositionFindAtStart) then
  266.       {Start at current column}
  267.       C := ColNo
  268.     else
  269.       {Start one beyond current cursor so repeated finds move on}
  270.       C := Succ(ColNo);
  271.     EdSetStartCol := C;
  272.   end;                       {EdSetStartCol}
  273.  
  274.   {***}
  275.   procedure EdFind;
  276.     {-Process find pattern command}
  277.   var
  278.     C : Integer;
  279.     P : PlineDesc;
  280.     M : BlockMarker;
  281.     Prompt : VarString;
  282.     HaveWindow : Boolean;
  283.  
  284.     {***}
  285.     procedure RestoreScreen;
  286.       {-Get rid of the prompt window if appropriate}
  287.  
  288.     begin                    {RestoreScreen}
  289.       if HaveWindow then
  290.         EdUpdateCursor;
  291.     end;                     {RestoreScreen}
  292.  
  293.   begin                      {EdFind}
  294.  
  295.     AbortEnable := True;
  296.  
  297.     {Don't update screen if keystrokes waiting}
  298.     HaveWindow := PromptForInput and (EditUsercommandInput = 0);
  299.  
  300.     if PromptForInput then begin
  301.       Prompt := EdGetMessage(323);
  302.       if HaveWindow then
  303.         EdWritePromptLine(Prompt);
  304.       EdGetSearchString(Succ(Length(Prompt)), 1,
  305.                         DefNoCols-Length(Prompt),
  306.                         DefNoCols-Length(Prompt),
  307.                         HaveWindow, SearchStr);
  308.     end;
  309.     if Abortcmd or EdStringEmpty(SearchStr) then begin
  310.       RestoreScreen;
  311.       Exit;
  312.     end;
  313.  
  314.     {Last operation was a find}
  315.     LastSearchOp := Find;
  316.  
  317.     Prompt := EdGetMessage(318);
  318.     if HaveWindow then
  319.       EdWritePromptLine(Prompt);
  320.     EdGetOptions(Succ(Length(Prompt)), 1, 10, 6, HaveWindow);
  321.  
  322.     {Remove the prompt box}
  323.     RestoreScreen;
  324.  
  325.     if Abortcmd then
  326.       Exit;
  327.  
  328.     if Blockfind then begin
  329.       {Search within marked block only}
  330.       EdBlockInit;
  331.       if GotError then
  332.         Exit;
  333.     end else if Global then
  334.       EdGlobalInit;
  335.  
  336.     EdWritePromptLine(EdGetMessage(326));
  337.  
  338.     {Search for the pattern}
  339.     with CurWin^ do begin
  340.  
  341.       {Set cursor to proper start position to avoid repeated finds}
  342.       C := EdSetStartCol(ColNo);
  343.  
  344.       {Do the work of the search}
  345.       P := EdScanpattern(CurLine, SearchStr, C);
  346.  
  347.     end;
  348.  
  349.     if EdPtrNotNil(P) then begin
  350.       {Move cursor to the position found}
  351.       M.Line := P;
  352.       if FindBackward or PositionFindAtStart then
  353.         M.Col := C
  354.       else
  355.         M.Col := C+Length(SearchStr);
  356.       EdJumpMarker(M);
  357.       {Show the found string clearly}
  358.       EdHighlightScreen(C, Pred(C+Length(SearchStr)), ScreenAttr[BordColor], True);
  359.  
  360.     end else if Abortcmd then
  361.       Exit
  362.  
  363.     else
  364.       {Pattern not found}
  365.       EdErrormsg(38);
  366.  
  367.   end;                       {EdFind}
  368.  
  369.   {***}
  370.   procedure EdFindReplace;
  371.     {-Process find pattern in text and replace command}
  372.   label
  373.     ExitPoint;
  374.   var
  375.     Ch : Char;
  376.     HaveWindow, NoReplace, NotFound, ShowUpdates : Boolean;
  377.     Fcol, Flength, Rlength : Integer;
  378.     P : PlineDesc;
  379.     M : BlockMarker;
  380.     CmdPrompt, Prompt : VarString;
  381.  
  382.     {***}
  383.     procedure RestoreScreen;
  384.       {-Get rid of the prompt window if appropriate}
  385.  
  386.     begin                    {RestoreScreen}
  387.       if HaveWindow then
  388.         EdUpdateCursor;
  389.     end;                     {RestoreScreen}
  390.  
  391.     {***}
  392.     procedure EdReplacestring(StartCol : Integer);
  393.       {-Perform string replacement}
  394.     var
  395.       EndOfSearch, EndOfReplace : Integer;
  396.       LenDiff : Integer;
  397.  
  398.     begin                    {EdReplacestring}
  399.       with CurWin^ do begin
  400.  
  401.         Modified := True;
  402.         EndOfSearch := StartCol+Length(SearchStr);
  403.         EndOfReplace := StartCol+Length(ReplaceStr);
  404.         LenDiff := Length(ReplaceStr)-Length(SearchStr);
  405.  
  406.         if LenDiff < 0 then begin
  407.           {Line getting shorter}
  408.           with CurLine^ do begin
  409.             Move(Txt^[EndOfSearch], Txt^[EndOfReplace], Succ(Bufflen-EndOfSearch));
  410.             FillChar(Txt^[Succ(Bufflen)+LenDiff], -LenDiff, Blank);
  411.           end;
  412.           {Fix up markers}
  413.           EdFixBlockInsertedSpace(CurLine, StartCol, LenDiff);
  414.           EdCheckNoMarker;
  415.           EdFixMarkInsertedSpace(CurLine, StartCol, LenDiff);
  416.  
  417.         end else if LenDiff > 0 then begin
  418.           {Line getting longer}
  419.           if not EdSizeline(CurLine, CurLine^.Bufflen+LenDiff, True) then begin
  420.             EdErrormsg(35);
  421.             {Stop searching}
  422.             Global := False;
  423.             Exit;
  424.           end;
  425.           with CurLine^ do
  426.             Move(Txt^[EndOfSearch], Txt^[EndOfReplace], Succ(Bufflen-EndOfReplace));
  427.           {Fix up markers}
  428.           EdFixBlockInsertedSpace(CurLine, StartCol, LenDiff);
  429.           EdFixMarkInsertedSpace(CurLine, StartCol, LenDiff);
  430.  
  431.         end;
  432.  
  433.         Move(ReplaceStr[1], CurLine^.Txt^[StartCol], Length(ReplaceStr));
  434.       end;
  435.     end;                     {EdReplacestring}
  436.  
  437.   begin                      {EdFindReplace}
  438.  
  439.     AbortEnable := True;
  440.     LastSearchOp := None;
  441.  
  442.     HaveWindow := PromptForInput and (EditUsercommandInput = 0);
  443.  
  444.     if PromptForInput then begin
  445.       Prompt := EdGetMessage(323);
  446.       if HaveWindow then
  447.         {Display the prompt}
  448.         EdWritePromptLine(Prompt);
  449.       EdGetSearchString(Succ(Length(Prompt)), 1,
  450.                         DefNoCols-Length(Prompt),
  451.                         DefNoCols-Length(Prompt),
  452.                         HaveWindow, SearchStr);
  453.     end;
  454.  
  455.     if Abortcmd or EdStringEmpty(SearchStr) then begin
  456.       RestoreScreen;
  457.       Exit;
  458.     end;
  459.  
  460.     if PromptForInput then begin
  461.       Prompt := EdGetMessage(338);
  462.       if HaveWindow then
  463.         {Display the prompt}
  464.         EdWritePromptLine(Prompt);
  465.       EdGetSearchString(Succ(Length(Prompt)), 1,
  466.                         DefNoCols-Length(Prompt),
  467.                         DefNoCols-Length(Prompt),
  468.                         HaveWindow, ReplaceStr);
  469.     end;
  470.     if Abortcmd then begin
  471.       RestoreScreen;
  472.       Exit;
  473.     end;
  474.  
  475.     {Save length for use in replace operations}
  476.     Rlength := Length(ReplaceStr);
  477.  
  478.     {Set up command prompt}
  479.     CmdPrompt := EdGetMessage(339);
  480.     LastSearchOp := Replace;
  481.  
  482.     Flength := Length(SearchStr);
  483.  
  484.     {Ask for options}
  485.     Prompt := EdGetMessage(337);
  486.     if HaveWindow then
  487.       {Draw new prompt}
  488.       EdWritePromptLine(Prompt);
  489.     EdGetOptions(Succ(Length(Prompt)), 1, 10, 6, HaveWindow);
  490.  
  491.     {Get rid of prompt box}
  492.     RestoreScreen;
  493.  
  494.     if Abortcmd then
  495.       Exit;
  496.  
  497.     if Blockfind then begin
  498.       EdBlockInit;
  499.       if GotError then
  500.         Exit;
  501.       Global := True;
  502.     end else if Global then
  503.       EdGlobalInit;
  504.  
  505.     {Search for the pattern}
  506.     NotFound := True;
  507.     ShowUpdates := True;
  508.     {Set cursor to proper start position to avoid repeated finds}
  509.     Fcol := EdSetStartCol(CurWin^.ColNo);
  510.  
  511.     with CurWin^ do
  512.       repeat
  513.  
  514.         if ShowUpdates then begin
  515.           EdWritePromptLine(EdGetMessage(326));
  516.           {Update entire screen at least once}
  517.           EdUpdateScreen;
  518.           {Show further updates only if previewing}
  519.           ShowUpdates := Preview;
  520.         end else
  521.           {Update only the command line}
  522.           EdWritePromptLine(EdGetMessage(327));
  523.  
  524.         {Find the next match}
  525.         P := EdScanpattern(CurLine, SearchStr, Fcol);
  526.  
  527.         if Abortcmd then
  528.           goto ExitPoint;
  529.  
  530.         if EdPtrIsNil(P) then
  531.  
  532.           {No match, force exit}
  533.           Global := False
  534.  
  535.         else begin
  536.  
  537.           {Found at least one occurrence of the pattern}
  538.           NotFound := False;
  539.  
  540.           {Move cursor to the position found}
  541.           M.Line := P;
  542.           if PositionFindAtStart or FindBackward then
  543.             M.Col := Fcol
  544.           else
  545.             M.Col := Fcol+Flength;
  546.           EdJumpMarker(M);
  547.  
  548.           {Assume the replacement will be done}
  549.           NoReplace := False;
  550.  
  551.           {Optional preview before replacement}
  552.           if Preview then begin
  553.             EdWritePromptLine('');
  554.             {Show the found string clearly}
  555.             EdHighlightScreen(Fcol, Pred(Fcol+Flength), ScreenAttr[BordColor], False);
  556.             {Prompt for action}
  557.             EdDisplayPromptWindow(CmdPrompt+EdGetMessage(329), 1, [^Y, ^N, ^A, ^Q], Ch);
  558.             if Abortcmd then
  559.               goto ExitPoint;
  560.             case Ch of
  561.               ^Y :
  562.                 EdReplacestring(Fcol);
  563.  
  564.               ^N :
  565.                 {Flag that replacement was not done}
  566.                 NoReplace := True;
  567.  
  568.               ^A :
  569.                 begin
  570.                   {Modify string and do the rest without asking}
  571.                   EdReplacestring(Fcol);
  572.                   Preview := False;
  573.                 end;
  574.  
  575.               ^Q :
  576.                 begin
  577.                   Global := False;
  578.                   NoReplace := True;
  579.                 end;
  580.             end;
  581.  
  582.           end else
  583.             {Modify without asking}
  584.             EdReplacestring(Fcol);
  585.  
  586.           if Global then begin
  587.             if FindBackward then begin
  588.               Dec(ColNo);
  589.               if (ColNo < Flength) then
  590.                 {No hope of further matches on this line}
  591.                 if EdPtrIsNil(CurLine^.Backlink) then
  592.                   {Force exit}
  593.                   Global := False
  594.                 else begin
  595.                   EdUpLine;
  596.                   EdRightLine;
  597.                 end;
  598.             end else begin
  599.               {Advance over the replace string to prevent left recursive search/replace}
  600.               if NoReplace and (Rlength = 0) then
  601.                 {Don't get stuck in place}
  602.                 ColNo := Succ(Fcol)
  603.               else
  604.                 ColNo := Fcol+Rlength;
  605.               if (ColNo+Flength > CurLine^.Bufflen) then
  606.                 {No hope of further matches on this line}
  607.                 if EdPtrIsNil(CurLine^.FwdLink) then begin
  608.                   {Force exit}
  609.                   Global := False;
  610.                   EdRightLine;
  611.                 end else begin
  612.                   EdDownLine;
  613.                   ColNo := 1;
  614.                 end;
  615.             end;
  616.             if Blockfind then
  617.               if not(EdCursorInBlock(CurLine, ColNo, True)) then
  618.                 {Cursor moved outside of block - force exit}
  619.                 Global := False;
  620.             {Set "find" column for next pass}
  621.             Fcol := ColNo;
  622.           end else begin
  623.             {Move the cursor past the last string found}
  624.             if not(FindBackward or PositionFindAtStart) then begin
  625.               if NoReplace then
  626.                 ColNo := Fcol+Flength
  627.               else
  628.                 ColNo := Fcol+Rlength;
  629.             end;
  630.           end;
  631.         end;
  632.  
  633.       until not Global;
  634.  
  635.     if NotFound then
  636.       {Pattern not found}
  637.       EdErrormsg(38);
  638.  
  639. ExitPoint:
  640.     EdRealign;
  641.  
  642.   end;                       {EdFindReplace}
  643.  
  644. begin
  645.   SearchStr := '';
  646.   ReplaceStr := '';
  647.   OptionStr := '';
  648. end.
  649.