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

  1. {                            MSBLOK.PAS
  2.                                MS 4.0
  3.                 Copyright (c) 1985, 87 by Borland International, Inc.         }
  4.  
  5. {$I msdirect.inc}
  6.  
  7. unit MsBlok;
  8.   {-Block move, copy and delete}
  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.  
  31. procedure EdBlockMove;
  32.   {-Process move block command}
  33.  
  34. procedure EdBlockCopy;
  35.   {-Process copy block command}
  36.  
  37. procedure EdBlockDelete;
  38.   {-Process delete block command}
  39.  
  40.   {==========================================================================}
  41.  
  42. implementation
  43.  
  44.   procedure EdBlockCleanup;
  45.     {-Reset markers and generally clean up when done with a block operation}
  46.  
  47.   begin                      {EdBlockCleanup}
  48.     Curwin^.Modified := True;
  49.     EdJumpMarker(Blockfrom);
  50.     EdRealign;
  51.     EdOffblock;
  52.     Blockhide := False;
  53.   end;                       {EdBlockCleanup}
  54.  
  55.   procedure EdBlockMove;
  56.     {-Process move block command}
  57.   var
  58.     WindFrom : Pwindesc;
  59.     F, T, C : BlockMarker;
  60.     Cline, Fright, Tright, Cright : PlineDesc;
  61.     M, ColFrom, ColTo, Colpos, NewColFrom, NewColTo : Integer;
  62.  
  63.   begin                      {EdBlockMove}
  64.  
  65.     {A block must be defined and unhidden}
  66.     if EdNoBlock then
  67.       Exit;
  68.  
  69.     {Don't allow the cursor within the block}
  70.     if EdCursorInBlock(Curwin^.Curline, Curwin^.Colno, False) then
  71.       Exit;
  72.  
  73.     {Provide some temporary margin for the move, which overall conserves memory}
  74.     FreeListSpace := FreeListPerm-(Maxlinelength shl 2);
  75.  
  76.     {Reset pagination on current window}
  77.     EdResetPageLine(Curwin);
  78.  
  79.     if (Blockfrom.Line = Blockto.Line) and (Curwin^.Curline = Blockfrom.Line) then begin
  80.  
  81.       {Move within a single line is special case}
  82.  
  83.       {Temporary variables}
  84.       ColFrom := Blockfrom.Col;
  85.       ColTo := Blockto.Col;
  86.       Colpos := Curwin^.Colno;
  87.       Cline := Curwin^.Curline;
  88.  
  89.       with Cline^ do begin
  90.  
  91.         if Colpos >= Bufflen then
  92.           {Size up line}
  93.           if not(EdSizeline(Cline, Succ(Colpos), True)) then begin
  94.             {Insufficient memory - should be impossible to reach here}
  95.             FreeListSpace := FreeListPerm;
  96.             Exit;
  97.           end;
  98.  
  99.         {Initialize buffer}
  100.         Move(Txt^[1], WorkBuf[1], Bufflen);
  101.  
  102.         if Colpos < ColFrom then begin
  103.  
  104.           {Cursor to left of marked block}
  105.           Move(Txt^[ColFrom], WorkBuf[Colpos], ColTo-ColFrom);
  106.           Move(Txt^[Colpos], WorkBuf[Colpos+ColTo-ColFrom], ColFrom-Colpos);
  107.           NewColFrom := Colpos;
  108.           NewColTo := Colpos+ColTo-ColFrom;
  109.  
  110.         end else begin
  111.  
  112.           {Cursor to right of marked block}
  113.           Move(Txt^[ColTo], WorkBuf[ColFrom], Colpos-ColTo);
  114.           Move(Txt^[ColFrom], WorkBuf[ColFrom+Colpos-ColTo], ColTo-ColFrom);
  115.           NewColFrom := ColFrom+Colpos-ColTo;
  116.           NewColTo := Colpos;
  117.  
  118.         end;
  119.  
  120.         {Copy buffer to current}
  121.         Move(WorkBuf[1], Txt^[1], Bufflen);
  122.  
  123.       end;
  124.  
  125.       {Save new block pointers}
  126.       Blockfrom.Col := NewColFrom;
  127.       Blockto.Col := NewColTo;
  128.  
  129.       {Fix up text markers}
  130.       if EdFlagSet(Cline, InMark) then
  131.         for M := 0 to MaxMarker do
  132.           with Marker[M] do
  133.             if Line = Cline then
  134.               if Colpos < ColFrom then begin
  135.                 if (Col >= Colpos) and (Col < ColFrom) then
  136.                   Col := Col+ColTo-ColFrom
  137.                 else if (Col >= ColFrom) and (Col < ColTo) then
  138.                   Col := Col-ColFrom+Colpos;
  139.               end else begin
  140.                 if (Col >= ColFrom) and (Col < ColTo) then
  141.                   Col := Col+Colpos-ColTo
  142.                 else if (Col >= ColTo) and (Col < Colpos) then
  143.                   Col := Col+ColFrom-ColTo;
  144.               end;
  145.  
  146.     end else begin
  147.  
  148.       {Move from one line to another}
  149.  
  150.       {Store temporary markers}
  151.       F := Blockfrom;
  152.       T := Blockto;
  153.       with C, Curwin^ do begin
  154.         Line := Curline;
  155.         Col := Colno;
  156.       end;
  157.  
  158.       {Determine whether all of any window topline or curline is in marked block}
  159.       WindFrom := EdFindWindow(Blockfrom.Line);
  160.       WindFrom^.Modified := True;
  161.       EdFixBaseLine(WindFrom);
  162.  
  163.       {Reset pagination progress for window from which move occurred}
  164.       EdResetPageLine(WindFrom);
  165.  
  166.       {Insert line breaks at the three markers}
  167.       {ORDER is IMPORTANT}
  168.       if C.Line = T.Line then
  169.         EdInsertLinePrimitive(C, Cright);
  170.       EdInsertLinePrimitive(T, Tright);
  171.       EdInsertLinePrimitive(F, Fright);
  172.       if C.Line <> T.Line then
  173.         EdInsertLinePrimitive(C, Cright);
  174.  
  175.       {Splice}
  176.       if T.Line = F.Line then begin
  177.         {Block contained within single line}
  178.         Fright^.Fwdlink := Cright;
  179.         EdJoinLinePrimitive(Fright, T.Col-F.Col);
  180.       end else begin
  181.         {Multiline block}
  182.         T.Line^.Fwdlink := Cright;
  183.         EdJoinLinePrimitive(T.Line, Pred(T.Col));
  184.       end;
  185.  
  186.       if T.Line = C.Line then begin
  187.         {Cursor on same line as end of block}
  188.         Tright^.Fwdlink := Fright;
  189.         EdJoinLinePrimitive(Tright, C.Col-T.Col);
  190.       end else begin
  191.         C.Line^.Fwdlink := Fright;
  192.         EdJoinLinePrimitive(C.Line, Pred(C.Col));
  193.       end;
  194.  
  195.       if F.Line = C.Line then begin
  196.         {Cursor on same line as begin of block}
  197.         T.Line^.Fwdlink := Tright;
  198.         EdJoinLinePrimitive(T.Line, Pred(T.Col+F.Col-C.Col));
  199.       end else begin
  200.         F.Line^.Fwdlink := Tright;
  201.         EdJoinLinePrimitive(F.Line, Pred(F.Col));
  202.       end;
  203.  
  204.       {Set block markers again}
  205.       if T.Line = C.Line then begin
  206.         Blockfrom.Line := F.Line;
  207.         Blockfrom.Col := F.Col+C.Col-T.Col;
  208.       end else
  209.         Blockfrom := C;
  210.  
  211.       if F.Line = T.Line then begin
  212.         Blockto.Line := C.Line;
  213.         Blockto.Col := C.Col+T.Col-F.Col;
  214.       end else
  215.         Blockto := T;
  216.  
  217.     end;
  218.  
  219.     EdBlockCleanup;
  220.  
  221.   end;                       {EdBlockMove}
  222.  
  223.   procedure EdBlockCopy;
  224.     {-Process copy block command}
  225.   var
  226.     C : BlockMarker;
  227.     Cline, Cright, P, Q, B, F, T : PlineDesc;
  228.     M, Colpos, ColFrom, ColTo, Blen : Integer;
  229.     Done : Boolean;
  230.  
  231.   begin                      {EdBlockCopy}
  232.  
  233.     {A block must be defined and visible}
  234.     if EdNoBlock then
  235.       Exit;
  236.  
  237.     {Don't allow cursor within block}
  238.     if EdCursorInBlock(Curwin^.Curline, Curwin^.Colno, True) then
  239.       Exit;
  240.  
  241.     Cline := Curwin^.Curline;
  242.     Colpos := Curwin^.Colno;
  243.     with C do begin
  244.       Line := Cline;
  245.       Col := Colpos;
  246.     end;
  247.     ColFrom := Blockfrom.Col;
  248.     ColTo := Blockto.Col;
  249.     F := Blockfrom.Line;
  250.     T := Blockto.Line;
  251.  
  252.     {Reset pagination progress}
  253.     EdResetPageLine(Curwin);
  254.  
  255.     if (F = T) and (Cline = F) then begin
  256.  
  257.       {Copy within a single line is special case}
  258.       with Cline^ do begin
  259.  
  260.         {Size up current line}
  261.         if Colpos > Bufflen then
  262.           Blen := Colpos
  263.         else
  264.           Blen := Bufflen;
  265.  
  266.         if not(EdSizeline(Cline, Succ(Blen+ColTo-ColFrom), True)) then begin
  267.           {Insufficient memory}
  268.           EdErrormsg(35);
  269.           Exit;
  270.         end;
  271.  
  272.         {Initialize buffer}
  273.         Move(Txt^[1], WorkBuf[1], Bufflen);
  274.  
  275.         {Copy the appropriate text}
  276.         Move(Txt^[ColFrom], WorkBuf[Colpos], ColTo-ColFrom);
  277.         if Blen <> Colpos then
  278.           Move(Txt^[Colpos], WorkBuf[Colpos+ColTo-ColFrom], Succ(Blen-Colpos));
  279.  
  280.         {Copy buffer to current}
  281.         Move(WorkBuf[1], Txt^[1], Bufflen);
  282.  
  283.       end;
  284.  
  285.       {Save new block markers}
  286.       Blockfrom.Col := Colpos;
  287.       Blockto.Col := Colpos+ColTo-ColFrom;
  288.  
  289.       {Fix up text markers}
  290.       if EdFlagSet(Cline, InMark) then
  291.         for M := 0 to MaxMarker do
  292.           with Marker[M] do
  293.             if Line = Cline then
  294.               if (Col >= Colpos) then
  295.                 Col := Col+ColTo-ColFrom;
  296.  
  297.     end else begin
  298.  
  299.       {Reduce available memory so we have something left to link with}
  300.       FreeListSpace := FreeListPerm+(Maxlinelength shl 1);
  301.  
  302.       {Break at the cursor position}
  303.       EdInsertLinePrimitive(C, Cright);
  304.       if Goterror then begin
  305.         FreeListSpace := FreeListPerm;
  306.         Exit;
  307.       end;
  308.  
  309.       {P will track the source text}
  310.       if Cline = F then
  311.         P := Cright
  312.       else
  313.         P := F;
  314.  
  315.       {Q will track the destination text}
  316.       Q := Cline;
  317.  
  318.       Done := False;
  319.  
  320.       repeat
  321.  
  322.         if (P = F) then begin
  323.  
  324.           if (P = T) then begin
  325.  
  326.             {Current source line contains begin and end of block}
  327.             Blen := ColTo-ColFrom;
  328.             B := EdMaktextdesc(Blen);
  329.             if EdPtrNotNil(B) then begin
  330.               {Copy text into buffer}
  331.               Move(P^.Txt^[ColFrom], B^.Txt^[1], Blen);
  332.               {Force exit for last line of block}
  333.               Done := True;
  334.             end;
  335.  
  336.           end else begin
  337.  
  338.             {First line of block}
  339.             Blen := Succ(P^.Bufflen-ColFrom);
  340.             B := EdMaktextdesc(Blen);
  341.             if EdPtrNotNil(B) then begin
  342.               {Copy text into buffer}
  343.               Move(P^.Txt^[ColFrom], B^.Txt^[1], Blen);
  344.               EdFwdPtr(P);
  345.             end;
  346.  
  347.           end;
  348.  
  349.         end else if (P = T) then begin
  350.  
  351.           {Last line of block}
  352.           Blen := Pred(ColTo);
  353.           B := EdMaktextdesc(Blen);
  354.           if EdPtrNotNil(B) then begin
  355.             {Copy text into buffer}
  356.             if Blen > 0 then
  357.               Move(P^.Txt^[1], B^.Txt^[1], Blen);
  358.             {Force exit}
  359.             Done := True;
  360.           end;
  361.  
  362.         end else begin
  363.  
  364.           {Middle of block}
  365.           Blen := P^.Bufflen;
  366.           B := EdMaktextdesc(Blen);
  367.           if EdPtrNotNil(B) then begin
  368.             {Copy text into buffer}
  369.             Move(P^.Txt^[1], B^.Txt^[1], Blen);
  370.             EdFwdPtr(P);
  371.           end;
  372.  
  373.         end;
  374.  
  375.         if EdPtrIsNil(B) then begin
  376.  
  377.           {Out of memory error already reported}
  378.           {Move b back to previous success and go on to the relink step}
  379.           B := Q;
  380.           Blen := Succ(EdTextLength(B));
  381.           {Correct blockto marker for as far as we got}
  382.           Blockto.Col := Blen;
  383.           Done := True;
  384.           Goterror := False;
  385.  
  386.         end else begin
  387.  
  388.           {Insert buffer between current q and cright}
  389.           Q^.Fwdlink := B;
  390.           B^.Backlink := Q;
  391.           B^.Fwdlink := Cright;
  392.           Cright^.Backlink := B;
  393.  
  394.           {Move q forward to b so that next line is inserted after b}
  395.           Q := B;
  396.  
  397.         end;
  398.  
  399.       until Done;            {Loop through all lines of block}
  400.  
  401.       {Get free list space back so we have room to link up}
  402.       FreeListSpace := FreeListPerm;
  403.  
  404.       {Join at begin and end}
  405.  
  406.       {Join right part of original current line to last buffer}
  407.       EdJoinLinePrimitive(B, Blen);
  408.       if Goterror then begin
  409.         EdBlockCleanup;
  410.         Exit;
  411.       end;
  412.  
  413.       {Join first buffer to left part of current line}
  414.       EdJoinLinePrimitive(Cline, Pred(Colpos));
  415.       if Goterror then begin
  416.         EdBlockCleanup;
  417.         Exit;
  418.       end;
  419.  
  420.       {Set block markers}
  421.       if F = T then begin
  422.         {Original block contained in a single line}
  423.         Blockto.Line := Cline;
  424.         Blockto.Col := Colpos+Blen;
  425.       end else
  426.         Blockto.Line := B;
  427.       Blockfrom.Line := Cline;
  428.       Blockfrom.Col := Colpos;
  429.  
  430.     end;
  431.  
  432.     EdBlockCleanup;
  433.  
  434.   end;                       {EdBlockCopy}
  435.  
  436.   procedure EdBlockDelete;
  437.     {-Process delete block command}
  438.   var
  439.     WindFrom : Pwindesc;
  440.     P, Q, Tright, Fright : PlineDesc;
  441.     C : BlockMarker;
  442.     M, ColFrom, ColTo, Blen : Integer;
  443.  
  444.   begin                      {EdBlockDelete}
  445.  
  446.     {A block must be defined and not hidden}
  447.     if EdNoBlock then
  448.       Exit;
  449.  
  450.     ColFrom := Blockfrom.Col;
  451.     ColTo := Blockto.Col;
  452.     WindFrom := EdFindWindow(Blockfrom.Line);
  453.  
  454.     {Don't delete from a background window when zoomed}
  455.     if Zoomed and (WindFrom <> Curwin) then
  456.       Exit;
  457.  
  458.     {Reset pagination progress}
  459.     EdResetPageLine(WindFrom);
  460.  
  461.     {Determine whether all of any window topline or curline is in marked block}
  462.     EdFixBaseLine(WindFrom);
  463.  
  464.     {Special case when block is within a single line}
  465.     if (Blockfrom.Line = Blockto.Line) then begin
  466.  
  467.       P := Blockfrom.Line;
  468.       Blen := EdTextLength(P);
  469.  
  470.       with P^ do begin
  471.  
  472.         {Initialize buffer}
  473.         Move(Txt^[1], WorkBuf[1], Bufflen);
  474.  
  475.         {Remove characters and right pad with blanks}
  476.         if ColTo <= Blen then
  477.           Move(Txt^[ColTo], WorkBuf[ColFrom], Succ(Blen-ColTo));
  478.         FillChar(WorkBuf[ColFrom+Succ(Blen-ColTo)], (ColTo-ColFrom), Blank);
  479.  
  480.         {Copy buffer to current}
  481.         Move(WorkBuf[1], Txt^[1], Bufflen);
  482.  
  483.       end;
  484.  
  485.       {Correct cursor}
  486.       if Curwin^.Curline = Blockfrom.Line then
  487.         Curwin^.Colno := Blockfrom.Col;
  488.  
  489.       {Fix up text markers}
  490.       if EdFlagSet(P, InMark) then
  491.         for M := 0 to MaxMarker do
  492.           with Marker[M] do
  493.             if Line = P then
  494.               if (Col >= ColTo) then
  495.                 Col := Col-ColTo+ColFrom
  496.               else if (Col >= ColFrom) then
  497.                 EdSetPtrNil(Line);
  498.  
  499.     end else begin
  500.  
  501.       {Store temporary marker}
  502.       with C do begin
  503.         Line := Curwin^.Curline;
  504.         Col := Curwin^.Colno;
  505.       end;
  506.  
  507.       {Provide some memory margin to get started deleting}
  508.       FreeListSpace := FreeListPerm-(Maxlinelength shl 1);
  509.  
  510.       {Insert line breaks before and after block}
  511.       EdInsertLinePrimitive(Blockfrom, Fright);
  512.       if Goterror then begin
  513.         FreeListSpace := FreeListPerm;
  514.         Exit;
  515.       end;
  516.       EdInsertLinePrimitive(Blockto, Tright);
  517.       if Goterror then begin
  518.         FreeListSpace := FreeListPerm;
  519.         Exit;
  520.       end;
  521.  
  522.       {Now scan and delete all lines in the block}
  523.       P := Fright;
  524.       repeat
  525.  
  526.         {Get the forward link now. push to undo destroys it}
  527.         Q := P^.Fwdlink;
  528.  
  529.         {Put line on undo stack if possible}
  530.         EdPushUndo(P);
  531.  
  532.         P := Q;
  533.  
  534.       until P = Tright;
  535.  
  536.       {Splice blockfrom to tright}
  537.       Blockfrom.Line^.Fwdlink := Tright;
  538.       EdJoinLinePrimitive(Blockfrom.Line, Pred(Blockfrom.Col));
  539.  
  540.       FreeListSpace := FreeListPerm;
  541.       EdRealign;
  542.       EdJumpMarker(C);
  543.  
  544.     end;
  545.  
  546.     WindFrom^.Modified := True;
  547.     {Indicate that markers are gone}
  548.     EdSetPtrNil(Blockto.Line);
  549.     EdOffblock;
  550.     Blockhide := True;
  551.  
  552.   end;                       {EdBlockDelete}
  553.  
  554.  
  555. end.
  556.