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

  1. {                           MSPTROP.PAS
  2.                               MS 4.0
  3.             Copyright (c) 1985, 87 by Borland International, Inc.              }
  4.  
  5. {$I msdirect.inc}
  6.  
  7. unit MsPtrOp;
  8.   {-Low level pointer operations for the Toolbox architecture}
  9.  
  10. interface
  11.  
  12. uses
  13.   Crt,                       {Basic video operations - standard unit}
  14.   Dos,                       {DOS interface - standard unit}
  15.   MsVars,                    {Global types and declarations}
  16.   MsScrn1;                   {Fast screen writing routines}
  17.  
  18.   {----------- Primitive operations}
  19.  
  20. function EdMemAvail(Size, Margin : Word) : Boolean;
  21.   {-Return true if enough contiguous memory exists on heap}
  22.  
  23. procedure EdFwdPtr(var P);
  24.   {-Change p (Plinedesc or Pwindesc) to its forward link}
  25.  
  26. procedure EdBackPtr(var P);
  27.   {-Change p (Plinedesc or Pwindesc) to its backward link}
  28.  
  29. function EdPtrIsNil(var P) : Boolean;
  30.   {-Return true if pointer p is nil}
  31.  
  32. function EdPtrNotNil(var P) : Boolean;
  33.   {-Return true if pointer p is not nil}
  34.  
  35. procedure EdSetPtrNil(var P);
  36.   {-Initialize pointer p to nil}
  37.  
  38. procedure EdToggleBoolean(var B : Boolean);
  39.   {-Toggle a boolean}
  40.  
  41.   {----------- Line oriented operations}
  42.  
  43. function EdTopofStream(W : Pwindesc) : PlineDesc;
  44.   {-Return pointer to first line in stream}
  45.  
  46. function EdTextLength(P : PlineDesc) : Integer;
  47.   {-Return the length of line text, 0 if all blank}
  48.  
  49. function EdLineIndent(P : PlineDesc) : Integer;
  50.   {-Return the indent of the specified line, 0 if line is empty}
  51.  
  52. procedure EdClrFlag(P : PlineDesc; Mask : Word);
  53.   {-Clear the line flag}
  54.  
  55. procedure EdSetFlag(P : PlineDesc; Mask : Word);
  56.   {-Set the line flag}
  57.  
  58. function EdFlagSet(P : PlineDesc; Mask : Word) : Boolean;
  59.   {-Return True if the mask flag is set for line p}
  60.  
  61. procedure EdChangeFlag(P : PlineDesc; FlagVal : Boolean; FlagPos : Word);
  62.   {-Change a line flag, setting UpdateScreen if change encountered}
  63.  
  64. procedure EdChangeStatus(NewVal : Word; var StoreLoc : Word);
  65.   {-Update a status value, setting UpdateScreen if a change has occurred}
  66.  
  67. function EdGetPageNum(P : PlineDesc) : Integer;
  68.   {-Return the page number of the line}
  69.  
  70. procedure EdSetPageNum(P : PlineDesc; Num : Integer);
  71.   {-Set the page number of the line}
  72.  
  73. procedure EdToggleTextMarker;
  74.   {-Toggle visibility of text markers}
  75.  
  76. procedure EdFixBlockInsertedSpace(P : PlineDesc; Start : Integer; Num : Integer);
  77.   {-Fix up block markers after blank space is inserted}
  78.  
  79. procedure EdFixMarkInsertedSpace(P : PlineDesc; Start : Integer; Num : Integer);
  80.   {-Fix up text markers after space is inserted in a line}
  81.  
  82. procedure EdFixBlockInsertedLine(ThisL, NextL : PlineDesc;
  83.                                  BreakCol : Integer;
  84.                                  Delta : Integer);
  85.   {-Fix up block markers after a line is inserted}
  86.  
  87. procedure EdFixMarkInsertedLine(ThisL, NextL : PlineDesc;
  88.                                 BreakCol : Integer;
  89.                                 Delta : Integer);
  90.   {-Fix up text markers after a new line is inserted}
  91.  
  92. procedure EdLinkbuffer(P, Q : PlineDesc);
  93.   {-Link line q after line p}
  94.  
  95. procedure EdBufferCurrentLine;
  96.   {-Keep an extra image of current line to allow restore via ^QL}
  97.  
  98. procedure EdBackupCurline(W : Pwindesc);
  99.   {-Move up curline as needed to fit into smaller window}
  100.  
  101. procedure EdMoveCursorIntoLine;
  102.   {-Set current column within line buffer}
  103.  
  104. procedure EdGotoColumn(Cno : Integer);
  105.   {-Go to column cno on current line}
  106.  
  107. procedure EdGotoLine(Lno : Integer);
  108.   {-Go to line lno of current window}
  109.  
  110. procedure EdWindowTopFile;
  111.   {-Go to top of window}
  112.  
  113. procedure EdTopScreen;
  114.   {-Move cursor to top of screen}
  115.  
  116. procedure EdBottomScreen;
  117.   {-Move cursor to bottom of screen}
  118.  
  119. procedure EdCompress(P : PlineDesc; Lmargin : Integer; var Col, Len : Integer);
  120.   {-Remove excess spaces internal to a line}
  121.  
  122. procedure EdUpdateFont(C : PrintCommandtype; var FontByte : Byte);
  123.   {-Toggle appropriate bit of packed font byte}
  124.  
  125. procedure EdCloneAttrFlags(P, Q : PlineDesc; Col : Integer);
  126.   {-Set font attribute flag for line q based on contents of p up to col}
  127.  
  128. function EdComputeEffectiveColNo(Attribs : Boolean; P : PlineDesc; Col : Integer) : Integer;
  129.   {-When attributes are displayed, correct column number for invisible characters}
  130.  
  131. function EdAdjustColno(P, Q : PlineDesc; Col : Integer) : Integer;
  132.   {-Adjust returned colno so effcol(p,col)=effcol(q,col)}
  133.  
  134.   {----------- Window oriented operations}
  135.  
  136. procedure EdWindowGoto(Wno : Byte);
  137.   {-Move cursor into window Wno, counted from top of screen}
  138.  
  139. function EdFindWindow(T : PlineDesc) : Pwindesc;
  140.   {-Return the window containing the designated line}
  141.  
  142. function EdFindWindesc(Wno : Byte) : Pwindesc;
  143.   {-return a window descriptor for a window number}
  144.  
  145. function EdWindowNumber : Byte;
  146.   {-Return the window number of the current window}
  147.  
  148. function EdGetWindowToDivide : Byte;
  149.   {-Return best window number to split in order to create a new window}
  150.  
  151. procedure EdResetTempMargin(W : Pwindesc; FullReset : Boolean);
  152.   {-Set temp margin back to fixed left margin when appropriate}
  153.  
  154. procedure EdResetPageLine(W : Pwindesc);
  155.   {-Reset the accurate pagination line after an edit operation occurs}
  156.  
  157. procedure EdZoomWindow(FixCurline : Boolean);
  158.   {-Make the current window fill the entire screen}
  159.  
  160. procedure EdWindowUp;
  161.   {-Process up window command}
  162.  
  163. procedure EdWindowDown;
  164.   {-Process down window command}
  165.  
  166. procedure EdRealignOne(W : Pwindesc);
  167.   {-Realign one window}
  168.  
  169. procedure EdRealign;
  170.   {-Realign windows over text streams}
  171.  
  172. procedure EdFixUpWindowSpan(P : PlineDesc);
  173.   {-When p is to be deleted, first fix up any other structures pointing to p}
  174.  
  175. procedure EdSetTextNo(W : Pwindesc);
  176.   {-Set the FirstTextNo of a window}
  177.  
  178. function EdLinkedWindow(W : Pwindesc) : Boolean;
  179.   {-return true if a window is linked to any others}
  180.  
  181. procedure EdResetWindowPrimitive(W : Pwindesc);
  182.   {-Low level routine for resetting window}
  183.  
  184. function EdNewstream : Word;
  185.   {-Return unique text stream identifier}
  186.  
  187. procedure EdChangeStreamName(Fname : Filepath);
  188.   {-Change name of current stream to fname}
  189.  
  190. procedure EdSetEvenTabs(var Tabs : TabArray);
  191.   {-Set the tab array to even tabs on the current default spacing}
  192.  
  193. procedure EdInitWindowSettings(W : Pwindesc);
  194.   {-Set window parameters to defaults}
  195.  
  196.   {----------- Block oriented operations}
  197.  
  198. function EdCursorInBlock(Q : PlineDesc; C : Integer; EndMarkOk : Boolean) : Boolean;
  199.   {-Return true if position q:c is in block}
  200.  
  201. function EdNoBlock : Boolean;
  202.   {-Return True if no block is marked and visible}
  203.  
  204. procedure EdOffblock;
  205.   {-Turn off Inblock bits for every text line in the system}
  206.  
  207. procedure EdCheckNoMarker;
  208.   {-If deletion operation has deleted all marked text, remove block markers altogether}
  209.  
  210. procedure EdBlockHide;
  211.   {-Toggle block display}
  212.  
  213. procedure EdFixBaseLine(WindFrom : Pwindesc);
  214.   {-Redefine window Topline and Curline before a block operation deletes them}
  215.  
  216. procedure EdBlockBegin;
  217.   {-Set block begin marker}
  218.  
  219. procedure EdBlockEnd;
  220.   {-Set block end marker}
  221.  
  222. procedure EdBlockWord;
  223.   {-Mark the current word as a block}
  224.  
  225.   {==========================================================================}
  226.  
  227. implementation
  228.  
  229. var
  230.   Nextstream : Word;         {Next stream ID to be assigned}
  231.  
  232.   {$L MSPTROP}
  233.   {$F+}
  234.   function EdGetEol(var Buf; C : Integer) : Integer; external;
  235.   {-Find end of a text buffer. Local to the unit, but called FAR}
  236.   {$F-}
  237.  
  238.   function EdPtrDiff(HighPt, LowPt : Pointer) : LongInt;
  239.     {-Return the number of bytes between point highpt^ and point lowpt^}
  240.   var
  241.     HighVal, LowVal : LongInt;
  242.  
  243.   begin                      {EdPtrDiff}
  244.     HighVal := LongInt(Seg(HighPt^)) shl 4+LongInt(Ofs(HighPt^));
  245.     LowVal := LongInt(Seg(LowPt^)) shl 4+LongInt(Ofs(LowPt^));
  246.     EdPtrDiff := HighVal-LowVal;
  247.   end;                       {EdPtrDiff}
  248.  
  249.   function EdHeapEnd : Pointer;
  250.     {-Return the last available location for the heap in a normalized pointer}
  251.  
  252.   begin                      {EdHeapEnd}
  253.     if Ofs(FreePtr^) = 0 then
  254.       {Free list is empty}
  255.       EdHeapEnd := Ptr(Seg(FreePtr^)+$1000, 0)
  256.     else
  257.       EdHeapEnd := Ptr(Seg(FreePtr^)+Ofs(FreePtr^) shr 4, 0);
  258.   end;                       {EdHeapEnd}
  259.  
  260.   function EdMemAvail(Size, Margin : Word) : Boolean;
  261.     {-Return true if enough contiguous memory exists on heap}
  262.   var
  263.     HighestHeapEnd, SaveHeapPtr : Pointer;
  264.  
  265.   begin                      {EdMemAvail}
  266.     {Compute highest heap end based on current freelist buffer size}
  267.     HighestHeapEnd := Ptr(Seg(FreePtr^)+$1000-Succ(Margin shr 4), 0);
  268.  
  269.     {Compare to actual freelist size}
  270.     if EdPtrDiff(HighestHeapEnd, EdHeapEnd) > 0 then
  271.       {Actual free list is bigger than buffer we guarantee}
  272.       HighestHeapEnd := EdHeapEnd;
  273.  
  274.     if EdPtrDiff(HighestHeapEnd, HeapPtr) > Size then
  275.       {There is space at the top of the heap for the request}
  276.       EdMemAvail := True
  277.     else begin
  278.       {Temporarily ignore whatever space is at the top of heap}
  279.       SaveHeapPtr := HeapPtr;
  280.       HeapPtr := EdHeapEnd;
  281.       EdMemAvail := (Size < MaxAvail);
  282.       HeapPtr := SaveHeapPtr;
  283.     end;
  284.   end;                       {EdMemAvail}
  285.  
  286.   procedure EdFwdPtr(var P);
  287.     {-Change p (Plinedesc or Pwindesc) to its forward link}
  288.   var
  289.     Pl : PlineDesc absolute P;
  290.  
  291.   begin                      {EdFwdPtr}
  292.     Pl := Pl^.Fwdlink;
  293.   end;                       {EdFwdPtr}
  294.  
  295.   procedure EdBackPtr(var P);
  296.     {-Change p (Plinedesc or Pwindesc) to its backward link}
  297.   var
  298.     Pl : PlineDesc absolute P;
  299.  
  300.   begin                      {EdBackPtr}
  301.     Pl := Pl^.Backlink;
  302.   end;                       {EdBackPtr}
  303.  
  304.   function EdPtrIsNil(var P) : Boolean;
  305.     {-Return true if pointer p is nil}
  306.   var
  307.     Pl : PlineDesc absolute P;
  308.  
  309.   begin                      {EdPtrIsNil}
  310.     EdPtrIsNil := (Pl = nil);
  311.   end;                       {EdPtrIsNil}
  312.  
  313.   function EdPtrNotNil(var P) : Boolean;
  314.     {-Return true if pointer p is not nil}
  315.   var
  316.     Pl : PlineDesc absolute P;
  317.  
  318.   begin                      {EdPtrNotNil}
  319.     EdPtrNotNil := (Pl <> nil);
  320.   end;                       {EdPtrNotNil}
  321.  
  322.   procedure EdSetPtrNil(var P);
  323.     {-Initialize pointer p to nil}
  324.   var
  325.     Pl : PlineDesc absolute P;
  326.  
  327.   begin                      {EdSetPtrNil}
  328.     Pl := nil;
  329.   end;                       {EdSetPtrNil}
  330.  
  331.   procedure EdToggleBoolean(var B : Boolean);
  332.     {-Toggle a boolean}
  333.  
  334.   begin                      {EdToggleBoolean}
  335.     B := not(B);
  336.   end;                       {EdToggleBoolean}
  337.  
  338.   function EdTopofStream(W : Pwindesc) : PlineDesc;
  339.     {-Return pointer to first line in stream}
  340.   var
  341.     P : PlineDesc;
  342.  
  343.   begin                      {EdTopofStream}
  344.     with W^ do
  345.       P := TopLine;
  346.     while EdPtrNotNil(P^.Backlink) do
  347.       EdBackPtr(P);
  348.     EdTopofStream := P;
  349.   end;                       {EdTopofStream}
  350.  
  351.   function EdFindWindow(T : PlineDesc) : Pwindesc;
  352.     {-Return the window containing the designated line}
  353.   var
  354.     P : PlineDesc;
  355.     W : Pwindesc;
  356.     Found : Boolean;
  357.  
  358.     function EdSearchBack(T, P : PlineDesc) : Boolean;
  359.       {-Starting at line p, search to top of stream for target line t}
  360.  
  361.     begin                    {EdSearchBack}
  362.       EdSearchBack := False;
  363.       while EdPtrNotNil(P) do
  364.         if P = T then begin
  365.           {Found target line}
  366.           EdSearchBack := True;
  367.           Exit;
  368.         end else
  369.           EdBackPtr(P);
  370.     end;                     {EdSearchBack}
  371.  
  372.     function EdSearchFwd(T, P : PlineDesc) : Boolean;
  373.       {-Starting at line p, search to bottom of stream for target line t}
  374.  
  375.     begin                    {EdSearchFwd}
  376.       EdSearchFwd := False;
  377.       while EdPtrNotNil(P) do
  378.         if P = T then begin
  379.           {Found target line}
  380.           EdSearchFwd := True;
  381.           Exit;
  382.         end else
  383.           EdFwdPtr(P);
  384.     end;                     {EdSearchFwd}
  385.  
  386.   begin                      {EdFindWindow}
  387.     W := Curwin;
  388.     repeat
  389.  
  390.       P := W^.TopLine;
  391.       Found := EdSearchFwd(T, P);
  392.       if not(Found) then
  393.         Found := EdSearchBack(T, P);
  394.       if Found then begin
  395.         EdFindWindow := W;
  396.         Exit;
  397.       end;
  398.  
  399.       EdFwdPtr(W);
  400.     until W = Curwin;
  401.  
  402.     {Window not found}
  403.     EdFindWindow := nil;
  404.   end;                       {EdFindWindow}
  405.  
  406.   function EdFindWindesc(Wno : Byte) : Pwindesc;
  407.     {-return a window descriptor for a window number}
  408.   var
  409.     W : Pwindesc;
  410.     I : Integer;
  411.  
  412.   begin                      {EdFindWindesc}
  413.     W := Window1;
  414.     I := 1;
  415.     while I < Wno do begin
  416.       EdFwdPtr(W);
  417.       Inc(I);
  418.     end;
  419.     EdFindWindesc := W;
  420.   end;                       {EdFindWindesc}
  421.  
  422.   function EdWindowNumber : Byte;
  423.     {-Return the window number of the current window}
  424.   var
  425.     W : Pwindesc;
  426.     I : Integer;
  427.  
  428.   begin                      {EdWindowNumber}
  429.     W := Window1;
  430.     I := 1;
  431.     while W <> Curwin do begin
  432.       EdFwdPtr(W);
  433.       Inc(I);
  434.     end;
  435.     EdWindowNumber := I;
  436.   end;                       {EdWindowNumber}
  437.  
  438.   function EdGetWindowToDivide : Byte;
  439.     {-Return best window number to split in order to create a new window}
  440.   var
  441.     W : Pwindesc;
  442.     Wno : Integer;
  443.  
  444.   begin                      {EdGetWindowToDivide}
  445.  
  446.     {Assume current window by default}
  447.     EdGetWindowToDivide := EdWindowNumber;
  448.  
  449.     {See if current window is OK to divide}
  450.     with Curwin^ do
  451.       if (Lastlineno-Firstlineno) > (MinWindowLines shl 1) then
  452.         Exit;
  453.  
  454.     {Start at top of screen and try the other windows}
  455.     W := Window1;
  456.     Wno := 1;
  457.     repeat
  458.       with W^ do
  459.         if (Lastlineno-Firstlineno) > (MinWindowLines shl 1) then begin
  460.           EdGetWindowToDivide := Wno;
  461.           Exit;
  462.         end;
  463.       EdFwdPtr(W);
  464.       Inc(Wno);
  465.     until W = Window1;
  466.  
  467.   end;                       {EdGetWindowToDivide}
  468.  
  469.   procedure EdResetTempMargin(W : Pwindesc; FullReset : Boolean);
  470.     {-Set temp margin back to fixed left margin when appropriate}
  471.   var
  472.     P : PlineDesc;
  473.     FoundMarginline, FoundBlankline : Boolean;
  474.  
  475.     procedure EdClearTempMargin(W : Pwindesc);
  476.       {-Clear the temporary margin}
  477.  
  478.     begin                    {EdClearTempMargin}
  479.       with W^ do begin
  480.         Wmargin := Lmargin;
  481.         EdSetPtrNil(WmarginLine);
  482.       end;
  483.     end;                     {EdClearTempMargin}
  484.  
  485.   begin                      {EdResetTempMargin}
  486.  
  487.     with W^ do
  488.       if FullReset then
  489.  
  490.         {Reset temp margin independent of conditions}
  491.         EdClearTempMargin(W)
  492.  
  493.       else if EdPtrIsNil(WmarginLine) then
  494.  
  495.         {Original marginline was deleted, reset the temp margin}
  496.         Wmargin := Lmargin
  497.  
  498.       else if Wmargin <> Lmargin then begin
  499.  
  500.         {Scan backward from current line}
  501.         P := Curline;
  502.         FoundBlankline := False;
  503.         FoundMarginline := False;
  504.  
  505.         while EdPtrNotNil(P) and not(FoundMarginline) do begin
  506.           if (P^.Txt^[1] = FormatChar) or (EdTextLength(P) = 0) then
  507.             FoundBlankline := True;
  508.           if P = WmarginLine then
  509.             FoundMarginline := True;
  510.           EdBackPtr(P);
  511.         end;
  512.  
  513.         if FoundMarginline then begin
  514.           if FoundBlankline then
  515.             EdClearTempMargin(W);
  516.           Exit;
  517.         end;
  518.  
  519.         {Scan forward from current line}
  520.         P := Curline;
  521.         FoundBlankline := False;
  522.         FoundMarginline := False;
  523.  
  524.         while EdPtrNotNil(P) and not(FoundMarginline) do begin
  525.           if (P^.Txt^[1] = FormatChar) or (EdTextLength(P) = 0) then
  526.             FoundBlankline := True;
  527.           if P = WmarginLine then
  528.             FoundMarginline := True;
  529.           EdFwdPtr(P);
  530.         end;
  531.  
  532.         if FoundMarginline and not(FoundBlankline) then
  533.           {Current line still in same paragraph}
  534.           Exit;
  535.  
  536.         {Marginline disappeared, or blank line found}
  537.         EdClearTempMargin(W);
  538.  
  539.       end;
  540.   end;                       {EdResetTempMargin}
  541.  
  542.   procedure EdResetPageLine(W : Pwindesc);
  543.     {-Reset the accurate pagination line after an edit operation occurs}
  544.   var
  545.     V : Pwindesc;
  546.     S : Integer;
  547.  
  548.   begin                      {EdResetPageLine}
  549.     V := W;
  550.     S := V^.Stream;
  551.     repeat
  552.       {Reset for all linked windows}
  553.       with V^ do
  554.         if PA and (Stream = S) then begin
  555.           PaginationDone := False;
  556.           EdSetPtrNil(PageLine);
  557.         end;
  558.       EdFwdPtr(V);
  559.     until V = W;
  560.   end;                       {EdResetPageLine}
  561.  
  562.   procedure EdZoomWindow(FixCurline : Boolean);
  563.     {-Make the current window fill the entire screen}
  564.  
  565.     procedure EdBackupAllCurline;
  566.       {-Assure curline is in visible region for all windows}
  567.     var
  568.       W : Pwindesc;
  569.  
  570.     begin                    {EdBackupAllCurline}
  571.       W := Curwin;
  572.       repeat
  573.         EdBackupCurline(W);
  574.         EdFwdPtr(W);
  575.       until W = Curwin;
  576.     end;                     {EdBackupAllCurline}
  577.  
  578.     procedure EdSetVisible(On : Boolean);
  579.       {-Set the visible flags for all windows}
  580.     var
  581.       W : Pwindesc;
  582.     begin                    {EdSetVisible}
  583.       W := Curwin;
  584.       repeat
  585.         W^.Visible := On;
  586.         EdFwdPtr(W);
  587.       until W = Curwin;
  588.     end;                     {EdSetVisible}
  589.  
  590.   begin                      {EdZoomWindow}
  591.     with Curwin^ do
  592.       if Zoomed then begin
  593.         {Undo the previous zoom}
  594.         Firstlineno := ZoomWin.Firstlineno;
  595.         Lastlineno := ZoomWin.Lastlineno;
  596.         EdSetTextNo(Curwin);
  597.         if FixCurline then
  598.           EdBackupAllCurline;
  599.         EdSetVisible(True);
  600.       end else begin
  601.         {Save current window screen position}
  602.         ZoomWin.Firstlineno := Firstlineno;
  603.         ZoomWin.Lastlineno := Lastlineno;
  604.         {Set window to fill full screen}
  605.         Firstlineno := LogtopScr;
  606.         Lastlineno := PhyscrRows;
  607.         EdSetTextNo(Curwin);
  608.         {Turn off visibility of all other windows}
  609.         EdSetVisible(False);
  610.         Visible := True;
  611.       end;
  612.     Zoomed := not(Zoomed);
  613.   end;                       {EdZoomWindow}
  614.  
  615.   procedure EdWindowUp;
  616.     {-Process up window command}
  617.   var
  618.     Rezoom : Boolean;
  619.  
  620.   begin                      {EdWindowUp}
  621.     Rezoom := Zoomed;
  622.     if Rezoom then
  623.       EdZoomWindow(False);
  624.     EdBackPtr(Curwin);
  625.     if Rezoom then
  626.       EdZoomWindow(False);
  627.     {Assure current line is positioned on screen}
  628.     EdBackupCurline(Curwin);
  629.   end;                       {EdWindowUp}
  630.  
  631.   procedure EdWindowDown;
  632.     {-Process down window command}
  633.   var
  634.     Rezoom : Boolean;
  635.  
  636.   begin                      {EdWindowDown}
  637.     Rezoom := Zoomed;
  638.     if Rezoom then
  639.       EdZoomWindow(False);
  640.     EdFwdPtr(Curwin);
  641.     if Rezoom then
  642.       EdZoomWindow(False);
  643.     {Assure current line is positioned on screen}
  644.     EdBackupCurline(Curwin);
  645.   end;                       {EdWindowDown}
  646.  
  647.   function EdCursorInBlock(Q : PlineDesc; C : Integer; EndMarkOk : Boolean) : Boolean;
  648.     {-Return true if position q:c is in block}
  649.   var
  650.     P : PlineDesc;
  651.     F, T : Integer;
  652.     Mnok : Boolean;
  653.  
  654.   begin                      {EdCursorInBlock}
  655.  
  656.     EdCursorInBlock := False;
  657.     P := Blockfrom.Line;
  658.     T := Blockto.Col;
  659.     F := Blockfrom.Col;
  660.     Mnok := not(EndMarkOk);
  661.  
  662.     while EdPtrNotNil(P) do begin
  663.  
  664.       if P = Q then begin
  665.         if P = Blockfrom.Line then
  666.           if P = Blockto.Line then
  667.             EdCursorInBlock := ((C > F) and (C < T)) or (Mnok and ((C = F) or (C = T)))
  668.           else
  669.             EdCursorInBlock := (C > F) or (Mnok and (C = F))
  670.         else if (P = Blockto.Line) then
  671.           EdCursorInBlock := (C < T) or (Mnok and (C = T))
  672.         else
  673.           EdCursorInBlock := True;
  674.         Exit;
  675.       end;
  676.  
  677.       if P = Blockto.Line then
  678.         {Exit loop}
  679.         EdSetPtrNil(P)
  680.       else
  681.         EdFwdPtr(P);
  682.  
  683.     end;
  684.   end;                       {EdCursorInBlock}
  685.  
  686.   function EdNoBlock : Boolean;
  687.     {-Return True if no block is marked and visible}
  688.  
  689.   begin                      {EdNoBlock}
  690.     EdNoBlock := Blockhide or
  691.     EdPtrIsNil(Blockfrom.Line) or EdPtrIsNil(Blockto.Line) or
  692.     ((Blockfrom.Line = Blockto.Line) and (Blockfrom.Col >= Blockto.Col));
  693.   end;                       {EdNoBlock}
  694.  
  695.   function EdTextLength(P : PlineDesc) : Integer;
  696.     {-Return the length of line text, 0 if all blank}
  697.   begin                      {EdTextLength}
  698.     with P^ do
  699.       EdTextLength := EdGetEol(Txt^, Bufflen);
  700.   end;                       {EdTextLength}
  701.  
  702.   procedure EdRealignOne(W : Pwindesc);
  703.     {-Realign one window}
  704.   var
  705.     P : PlineDesc;
  706.     Size : Integer;
  707.  
  708.   begin                      {EdRealignOne}
  709.     with W^ do begin
  710.       {Realign this window}
  711.       Lineno := 1;
  712.       {Topline must always be defined!}
  713.       P := TopLine;
  714.       {Account for zoomed windows - each window effectively has full screen}
  715.       if Zoomed then begin
  716.         if TL then
  717.           Size := PhyscrRows-(LogtopScr+2)
  718.         else
  719.           Size := PhyscrRows-Succ(LogtopScr);
  720.       end else
  721.         Size := Lastlineno-Firsttextno;
  722.       {Curline must always be equal to or forward from Topline!}
  723.       while (P <> Curline) and EdPtrNotNil(P) do begin
  724.         {Scan until we find the current line}
  725.         EdFwdPtr(P);
  726.         if Lineno > Size then
  727.           EdFwdPtr(TopLine)
  728.         else
  729.           Inc(Lineno);
  730.       end;
  731.     end;
  732.   end;                       {EdRealignOne}
  733.  
  734.   procedure EdRealign;
  735.     {-Realign windows over text streams}
  736.   var
  737.     W : Pwindesc;
  738.  
  739.   begin                      {EdRealign}
  740.     W := Window1;
  741.     repeat
  742.       EdRealignOne(W);
  743.       EdFwdPtr(W);
  744.     until W = Window1;
  745.   end;                       {EdRealign}
  746.  
  747.   function EdLineIndent(P : PlineDesc) : Integer;
  748.     {-Return the indent of the specified line, 0 if line is empty}
  749.   var
  750.     I : Integer;
  751.  
  752.   begin                      {EdLineIndent}
  753.     with P^ do begin
  754.       I := 1;
  755.       while (I < Bufflen) and (Txt^[I] = Blank) do
  756.         Inc(I);
  757.       if I >= Bufflen then
  758.         {Line is all blank}
  759.         I := 0;
  760.     end;
  761.     EdLineIndent := I;
  762.   end;                       {EdLineIndent}
  763.  
  764.   procedure EdClrFlag(P : PlineDesc; Mask : Word);
  765.     {-Clear the line flag}
  766.  
  767.   begin                      {EdClrFlag}
  768.     P^.Flags := P^.Flags and not(Mask);
  769.   end;                       {EdClrFlag}
  770.  
  771.   procedure EdSetFlag(P : PlineDesc; Mask : Word);
  772.     {-Set the line flag}
  773.  
  774.   begin                      {EdSetFlag}
  775.     P^.Flags := P^.Flags or Mask;
  776.   end;                       {EdSetFlag}
  777.  
  778.   function EdFlagSet(P : PlineDesc; Mask : Word) : Boolean;
  779.     {-Return True if the mask flag is set for line p}
  780.  
  781.   begin                      {EdFlagSet}
  782.     EdFlagSet := (P^.Flags and Mask) <> 0;
  783.   end;                       {EdFlagSet}
  784.  
  785.   procedure EdChangeFlag(P : PlineDesc; FlagVal : Boolean; FlagPos : Word);
  786.     {-Change a line flag, setting UpdateScreen if change encountered}
  787.  
  788.   begin                      {EdChangeFlag}
  789.     if FlagVal then begin
  790.       {Setting a flag}
  791.       if not(EdFlagSet(P, FlagPos)) then begin
  792.         UpdateScreen := True;
  793.         EdSetFlag(P, FlagPos);
  794.       end;
  795.     end else if EdFlagSet(P, FlagPos) then begin
  796.       {Clearing a flag}
  797.       UpdateScreen := True;
  798.       EdClrFlag(P, FlagPos);
  799.     end;
  800.   end;                       {EdChangeFlag}
  801.  
  802.   procedure EdChangeStatus(NewVal : Word; var StoreLoc : Word);
  803.     {-Update a status value, setting UpdateScreen if a change has occurred}
  804.  
  805.   begin                      {EdChangeStatus}
  806.     if NewVal <> StoreLoc then begin
  807.       UpdateScreen := True;
  808.       StoreLoc := NewVal;
  809.     end;
  810.   end;                       {EdChangeStatus}
  811.  
  812.   function EdGetPageNum(P : PlineDesc) : Integer;
  813.     {-Return the page number of the line}
  814.  
  815.   begin                      {EdGetPageNum}
  816.     if EdPtrIsNil(P) then
  817.       EdGetPageNum := 0
  818.     else
  819.       EdGetPageNum := (P^.Flags and MaxPage);
  820.   end;                       {EdGetPageNum}
  821.  
  822.   procedure EdSetPageNum(P : PlineDesc; Num : Integer);
  823.     {-Set the page number of the line}
  824.  
  825.   begin                      {EdSetPageNum}
  826.     with P^ do
  827.       Flags := (Flags and not(MaxPage)) or (Num and MaxPage);
  828.   end;                       {EdSetPageNum}
  829.  
  830.   procedure EdToggleTextMarker;
  831.     {-Toggle visibility of text markers}
  832.   var
  833.     M : Integer;
  834.  
  835.   begin                      {EdToggleTextMarker}
  836.     Markhide := not(Markhide);
  837.     {Set line flags}
  838.     for M := 0 to MaxMarker do
  839.       with Marker[M] do
  840.         if EdPtrNotNil(Line) then
  841.           if Markhide then
  842.             EdClrFlag(Line, InMark)
  843.           else
  844.             EdSetFlag(Line, InMark);
  845.   end;                       {EdToggleTextMarker}
  846.  
  847.   procedure EdFixUpWindowSpan(P : PlineDesc);
  848.     {-When p is to be deleted, first fix up any other structures pointing to p}
  849.   var
  850.     W : Pwindesc;
  851.     T : PlineDesc;
  852.  
  853.   begin                      {EdFixUpWindowSpan}
  854.  
  855.     {Check window Toplines, Curlines, and shortening window's span}
  856.     W := Window1;
  857.     repeat
  858.       with W^ do begin
  859.         if P = TopLine then begin
  860.           {Deleting the top line of a window}
  861.           if EdPtrIsNil(P^.Backlink) then begin
  862.             if EdPtrIsNil(P^.Fwdlink) then begin
  863.               {Deleting only line in file, must be linked windows}
  864.               Curline := Curwin^.Curline;
  865.               TopLine := Curline;
  866.             end else begin
  867.               {Deleting first line of file}
  868.               if P = Curline then begin
  869.                 EdFwdPtr(Curline);
  870.                 Lineno := 1;
  871.               end else
  872.                 Dec(Lineno);
  873.               EdFwdPtr(TopLine);
  874.             end;
  875.           end else begin
  876.             {Somewhere in middle or end of file}
  877.             if P = Curline then begin
  878.               EdBackPtr(Curline);
  879.               Lineno := 1;
  880.             end;
  881.             EdBackPtr(TopLine);
  882.           end;
  883.         end else if P = Curline then begin
  884.           {Deleting the current line of a window}
  885.           if EdPtrIsNil(P^.Fwdlink) then begin
  886.             {Last line in file}
  887.             EdBackPtr(Curline);
  888.             Dec(Lineno);
  889.           end else
  890.             EdFwdPtr(Curline);
  891.         end else begin
  892.           {Check for line in the middle of window}
  893.           T := TopLine;
  894.           while T <> Curline do
  895.             if T = P then begin
  896.               {Try to advance curline}
  897.               if EdPtrIsNil(Curline^.Fwdlink) then
  898.                 Dec(Lineno)
  899.               else
  900.                 EdFwdPtr(Curline);
  901.               {Force exit}
  902.               T := Curline;
  903.             end else
  904.               EdFwdPtr(T);
  905.         end;
  906.       end;
  907.       EdFwdPtr(W);
  908.     until W = Window1;
  909.  
  910.   end;                       {EdFixUpWindowSpan}
  911.  
  912.   procedure EdFixBlockInsertedSpace(P : PlineDesc; Start : Integer; Num : Integer);
  913.     {-Fix up block markers after blank space is inserted}
  914.  
  915.   begin                      {EdFixBlockInsertedSpace}
  916.     if (P = Blockfrom.Line) then
  917.       if (Start < Blockfrom.Col) then
  918.         Blockfrom.Col := Blockfrom.Col+Num;
  919.     if (P = Blockto.Line) then
  920.       if (Start < Blockto.Col) then
  921.         Blockto.Col := Blockto.Col+Num;
  922.   end;                       {EdFixBlockInsertedSpace}
  923.  
  924.   procedure EdFixMarkInsertedSpace(P : PlineDesc; Start : Integer; Num : Integer);
  925.     {-Fix up text markers after space is inserted in a line}
  926.   var
  927.     M : Integer;
  928.  
  929.   begin                      {EdFixMarkInsertedSpace}
  930.     if EdFlagSet(P, InMark) then
  931.       for M := 0 to MaxMarker do
  932.         with Marker[M] do
  933.           if (Line = P) then
  934.             if (Col >= Start) then begin
  935.               Col := Col+Num;
  936.               if Col < 1 then
  937.                 Col := 1;
  938.             end;
  939.   end;                       {EdFixMarkInsertedSpace}
  940.  
  941.   procedure EdFixBlockInsertedLine(ThisL, NextL : PlineDesc;
  942.                                    BreakCol : Integer;
  943.                                    Delta : Integer);
  944.     {-Fix up block markers after a line is inserted}
  945.  
  946.   begin                      {EdFixBlockInsertedLine}
  947.     if not(Blockhide) and EdFlagSet(ThisL, InBlock) then
  948.       EdSetFlag(NextL, InBlock);
  949.     if (ThisL = Blockfrom.Line) then
  950.       if (BreakCol <= Blockfrom.Col) then begin
  951.         Blockfrom.Line := NextL;
  952.         Blockfrom.Col := Blockfrom.Col-Delta;
  953.         EdClrFlag(ThisL, InBlock);
  954.       end;
  955.     if (ThisL = Blockto.Line) then
  956.       if (BreakCol < Blockto.Col) then begin
  957.         Blockto.Line := NextL;
  958.         Blockto.Col := Blockto.Col-Delta;
  959.       end else
  960.         EdClrFlag(NextL, InBlock);
  961.   end;                       {EdFixBlockInsertedLine}
  962.  
  963.   procedure EdFixMarkInsertedLine(ThisL, NextL : PlineDesc;
  964.                                   BreakCol : Integer;
  965.                                   Delta : Integer);
  966.     {-Fix up text markers after a new line is inserted}
  967.   var
  968.     MarkGone : Boolean;
  969.     M : Integer;
  970.  
  971.   begin                      {EdFixMarkInsertedLine}
  972.     MarkGone := True;
  973.     for M := 0 to MaxMarker do
  974.       with Marker[M] do
  975.         if (Line = ThisL) then
  976.           if (Col >= BreakCol) then begin
  977.             Col := Succ(Col-Delta);
  978.             Line := NextL;
  979.             EdSetFlag(NextL, InMark);
  980.           end else
  981.             MarkGone := False;
  982.     if MarkGone then
  983.       EdClrFlag(ThisL, InMark);
  984.   end;                       {EdFixMarkInsertedLine}
  985.  
  986.   procedure EdOffblock;
  987.     {-Turn off Inblock bits for every text line in the system}
  988.   var
  989.     W : Pwindesc;
  990.     P, Q : PlineDesc;
  991.  
  992.   begin                      {EdOffblock}
  993.     {Start with current window}
  994.     W := Curwin;
  995.     repeat
  996.       {Do this to every window}
  997.       P := W^.TopLine;
  998.       Q := P;
  999.       while EdPtrNotNil(P) do begin
  1000.         EdClrFlag(P, InBlock);
  1001.         EdBackPtr(P);
  1002.       end;
  1003.       while EdPtrNotNil(Q) do begin
  1004.         EdClrFlag(Q, InBlock);
  1005.         EdFwdPtr(Q);
  1006.       end;
  1007.       EdFwdPtr(W);
  1008.     until W = Curwin;
  1009.   end;                       {EdOffblock}
  1010.  
  1011.   procedure EdSetTextNo(W : Pwindesc);
  1012.     {-Set the FirstTextNo of a window}
  1013.  
  1014.   begin                      {EdSetTextNo}
  1015.     with W^ do
  1016.       if TL then
  1017.         Firsttextno := Firstlineno+2
  1018.       else
  1019.         Firsttextno := Succ(Firstlineno);
  1020.   end;                       {EdSetTextNo}
  1021.  
  1022.   function EdLinkedWindow(W : Pwindesc) : Boolean;
  1023.     {-Return true if a window is linked to any others}
  1024.   var
  1025.     V : Pwindesc;
  1026.     Wstream : Word;
  1027.  
  1028.   begin                      {EdLinkedWindow}
  1029.     Wstream := W^.Stream;
  1030.     V := W^.Fwdlink;
  1031.     while V <> W do
  1032.       if V^.Stream = Wstream then begin
  1033.         EdLinkedWindow := True;
  1034.         Exit;
  1035.       end else
  1036.         EdFwdPtr(V);
  1037.     EdLinkedWindow := False;
  1038.   end;                       {EdLinkedWindow}
  1039.  
  1040.   function EdBlockDiscontinuous : Boolean;
  1041.     {-Return true if block is not within a continuous text stream}
  1042.   var
  1043.     P : PlineDesc;
  1044.  
  1045.   begin                      {EdBlockDiscontinuous}
  1046.     EdBlockDiscontinuous := True;
  1047.     P := Blockfrom.Line;
  1048.     while EdPtrNotNil(P) do
  1049.       if P = Blockto.Line then begin
  1050.         {Block is continuous if columns are legal}
  1051.         EdBlockDiscontinuous := (Blockfrom.Line = Blockto.Line) and (Blockfrom.Col >= Blockto.Col);
  1052.         Exit;
  1053.       end else
  1054.         EdFwdPtr(P);
  1055.   end;                       {EdBlockDiscontinuous}
  1056.  
  1057.   procedure EdResetWindowPrimitive(W : Pwindesc);
  1058.     {-Low level routine for resetting window}
  1059.  
  1060.   begin                      {EdResetWindowPrimitive}
  1061.     with W^ do begin
  1062.       Curline := TopLine;
  1063.       Clineno := 1;
  1064.       Lineno := 1;
  1065.       Colno := 1;
  1066.       Leftedge := 1;
  1067.     end;
  1068.   end;                       {EdResetWindowPrimitive}
  1069.  
  1070.   function EdNewstream : Word;
  1071.     {-Return unique text stream identifier}
  1072.  
  1073.   begin                      {EdNewstream}
  1074.     EdNewstream := Nextstream;
  1075.     Nextstream := Succ(Nextstream) mod MaxInt;
  1076.   end;                       {EdNewstream}
  1077.  
  1078.   procedure EdChangeStreamName(Fname : Filepath);
  1079.     {-Change name of current stream to fname}
  1080.   var
  1081.     W : Pwindesc;
  1082.     S : Word;
  1083.  
  1084.   begin                      {EdChangeStreamName}
  1085.     S := Curwin^.Stream;
  1086.     W := Curwin;
  1087.     repeat
  1088.       if W^.Stream = S then
  1089.         W^.Filename := Fname;
  1090.       EdFwdPtr(W);
  1091.     until W = Curwin;
  1092.   end;                       {EdChangeStreamName}
  1093.  
  1094.   procedure EdCheckNoMarker;
  1095.     {-If deletion operation has deleted all marked text, remove block markers altogether}
  1096.  
  1097.   begin                      {EdChecknomarker}
  1098.     {Get out fast if no block now}
  1099.     if EdPtrIsNil(Blockfrom.Line) or (Blockfrom.Line <> Blockto.Line) then
  1100.       Exit;
  1101.     if Blockfrom.Col >= Blockto.Col then begin
  1102.       EdSetPtrNil(Blockfrom.Line);
  1103.       EdSetPtrNil(Blockto.Line);
  1104.       EdOffblock;
  1105.     end;
  1106.   end;                       {EdChecknomarker}
  1107.  
  1108.   procedure EdSetEvenTabs(var Tabs : TabArray);
  1109.     {-Set the tab array to even tabs on the current default spacing}
  1110.   var
  1111.     I, TabPos : Integer;
  1112.  
  1113.   begin                      {EdSetEvenTabs}
  1114.     for I := 1 to MaxNumTabs do begin
  1115.       TabPos := Succ(SaveTabSize*I);
  1116.       if TabPos <= Maxlinelength then
  1117.         Tabs[I] := TabPos
  1118.       else
  1119.         Tabs[I] := 0;
  1120.     end;
  1121.   end;                       {EdSetEvenTabs}
  1122.  
  1123.   procedure EdInitWindowSettings(W : Pwindesc);
  1124.     {-Set window parameters to defaults}
  1125.  
  1126.   begin                      {EdInitWindowSettings}
  1127.     with W^ do begin
  1128.       Insertflag := SaveInsertMode;
  1129.       AI := SaveIndentMode;
  1130.       WW := SaveWWmode;
  1131.       TL := SaveTabMode;
  1132.       JU := SaveJustMode;
  1133.       PA := SavePageMode;
  1134.       AT := SaveAttrMode;
  1135.       FT := SaveFTmode;
  1136.       CW := SaveCompressWrap;
  1137.       Lmargin := SaveLeftMargin;
  1138.       Rmargin := SaveRightMargin;
  1139.       PageLen := SavePageLen;
  1140.       Tmargin := SaveTopMargin;
  1141.       Bmargin := SaveBottomMargin;
  1142.       Filename := NoFile;
  1143.       Modified := False;
  1144.       Visible := True;
  1145.       Clineno := 1;
  1146.       Crelpos := 00;
  1147.       PaginationDone := False;
  1148.       EdSetPtrNil(PageLine);
  1149.       if PA then
  1150.         Leftcol := 2
  1151.       else
  1152.         Leftcol := 0;
  1153.       Leftedge := 1;
  1154.       EdSetEvenTabs(Tabs);
  1155.       EdResetTempMargin(W, True);
  1156.     end;
  1157.   end;                       {EdInitWindowSettings}
  1158.  
  1159.   procedure EdLinkbuffer(P, Q : PlineDesc);
  1160.     {-Link line q after line p}
  1161.  
  1162.   begin                      {EdLinkbuffer}
  1163.     Q^.Backlink := P;
  1164.     Q^.Fwdlink := P^.Fwdlink;
  1165.     P^.Fwdlink := Q;
  1166.     if EdPtrNotNil(Q^.Fwdlink) then
  1167.       Q^.Fwdlink^.Backlink := Q;
  1168.   end;                       {EdLinkbuffer}
  1169.  
  1170.   procedure EdBufferCurrentLine;
  1171.     {-Keep an extra image of current line to allow restore via ^QL}
  1172.   var
  1173.     Len : Integer;
  1174.  
  1175.   begin                      {EdBufferCurrentLine}
  1176.     with Curwin^ do begin
  1177.  
  1178.       Len := Curline^.Bufflen;
  1179.  
  1180.       {Store the text and flags of the current line}
  1181.       with CurlineBuf^ do begin
  1182.         Bufflen := Len;
  1183.         Flags := Curline^.Flags;
  1184.         Move(Curline^.Txt^[1], Txt^[1], Len);
  1185.       end;
  1186.  
  1187.       {Store the current column number}
  1188.       Curlinecol := Colno;
  1189.  
  1190.       {Store block columns and lines}
  1191.       if Curline = Blockfrom.Line then
  1192.         Curlinefrom.Col := Blockfrom.Col;
  1193.       Curlinefrom.Line := Blockfrom.Line;
  1194.  
  1195.       if Curline = Blockto.Line then
  1196.         Curlineto.Col := Blockto.Col;
  1197.       Curlineto.Line := Blockto.Line;
  1198.  
  1199.     end;
  1200.   end;                       {EdBufferCurrentLine}
  1201.  
  1202.   procedure EdBackupCurline(W : Pwindesc);
  1203.     {-Move curline up as needed to fit into smaller window}
  1204.  
  1205.   begin                      {EdBackupCurline}
  1206.     with W^ do
  1207.       while Lineno > Succ(Lastlineno-Firsttextno) do begin
  1208.         {Fix up the pointers}
  1209.         EdFwdPtr(TopLine);
  1210.         {Alternate behavior, replace previous line with --> EdBackPtr(Curline);}
  1211.         Dec(Lineno);
  1212.       end;
  1213.   end;                       {EdBackupCurline}
  1214.  
  1215.   procedure EdMoveCursorIntoLine;
  1216.     {-Set current column within line buffer}
  1217.  
  1218.   begin                      {EdMoveCursorIntoLine}
  1219.     with Curwin^ do
  1220.       if Colno > Curline^.Bufflen then
  1221.         Colno := Curline^.Bufflen;
  1222.   end;                       {EdMoveCursorIntoLine}
  1223.  
  1224.   procedure EdGotoColumn(Cno : Integer);
  1225.     {-Go to column cno on current line}
  1226.  
  1227.   begin                      {EdGotoColumn}
  1228.     Curwin^.Colno := Cno;
  1229.   end;                       {EdGotoColumn}
  1230.  
  1231.   procedure EdGotoLine(Lno : Integer);
  1232.     {-Go to line Lno of current window}
  1233.   var
  1234.     P : PlineDesc;
  1235.     I : Integer;
  1236.  
  1237.   begin                      {EdGotoLine}
  1238.     with Curwin^ do begin
  1239.       {Go to first line of file}
  1240.       P := EdTopofStream(Curwin);
  1241.       I := 1;
  1242.       {Count lines to the right one}
  1243.       while (I < Lno) and EdPtrNotNil(P^.Fwdlink) do begin
  1244.         Inc(I);
  1245.         EdFwdPtr(P);
  1246.       end;
  1247.       Curline := P;
  1248.       TopLine := P;
  1249.       Lineno := 1;
  1250.       Clineno := I;
  1251.     end;
  1252.   end;                       {EdGotoLine}
  1253.  
  1254.   procedure EdWindowTopFile;
  1255.     {-Go to top of file}
  1256.   var
  1257.     P : PlineDesc;
  1258.  
  1259.   begin                      {EdWindowTopFile}
  1260.     P := EdTopofStream(Curwin);
  1261.     Curwin^.TopLine := P;
  1262.     EdResetWindowPrimitive(Curwin);
  1263.   end;                       {EdWindowTopFile}
  1264.  
  1265.   procedure EdUpdateFont(C : PrintCommandtype; var FontByte : Byte);
  1266.     {-Toggle appropriate bit of packed font byte}
  1267.   var
  1268.     Mask : Byte;
  1269.  
  1270.   begin                      {EdUpdateFont}
  1271.     Mask := 1 shl Ord(C);
  1272.     if (FontByte and Mask) = 0 then
  1273.       FontByte := FontByte or Mask
  1274.     else
  1275.       FontByte := FontByte and not(Mask);
  1276.   end;                       {EdUpdateFont}
  1277.  
  1278.   procedure EdCloneAttrFlags(P, Q : PlineDesc; Col : Integer);
  1279.     {-Set font attribute flag for line q based on contents of p up to col}
  1280.   var
  1281.     FontByte : Byte;
  1282.     C : PrintCommandtype;
  1283.     I : Integer;
  1284.  
  1285.   begin                      {EdCloneAttrFlags}
  1286.  
  1287.     {Get the font descriptor at start of original line}
  1288.     FontByte := P^.Font;
  1289.  
  1290.     {Scan the line up to the break point}
  1291.     with P^ do begin
  1292.       if Col > Bufflen then
  1293.         Col := Succ(Bufflen);
  1294.       for I := 1 to Pred(Col) do begin
  1295.         C := PrintMap[Txt^[I]];
  1296.         if C <> PrtNone then
  1297.           EdUpdateFont(C, FontByte);
  1298.       end;
  1299.     end;
  1300.  
  1301.     {Give the font descriptor to the new line}
  1302.     Q^.Font := FontByte;
  1303.     {Assume font will change in new line, later updated by background process}
  1304.     EdSetFlag(Q, NewAttr);
  1305.  
  1306.   end;                       {EdCloneAttrFlags}
  1307.  
  1308.   function EdComputeEffectiveColNo(Attribs : Boolean; P : PlineDesc; Col : Integer) : Integer;
  1309.     {-When attributes are displayed, correct column number for invisible characters}
  1310.   var
  1311.     Ipos, Opos : Integer;
  1312.  
  1313.   begin                      {EdComputeEffectiveColNo}
  1314.     if Attribs then
  1315.       with P^ do begin
  1316.  
  1317.         Opos := 0;
  1318.         for Ipos := 1 to Col do
  1319.           if Ipos > Bufflen then
  1320.             Inc(Opos)
  1321.           else if PrintMap[Txt^[Ipos]] = PrtNone then
  1322.             Inc(Opos);
  1323.  
  1324.         {Correct if cursor is on a control character}
  1325.         if Opos = 0 then
  1326.           EdComputeEffectiveColNo := 1
  1327.         else if (Col > Bufflen) or (PrintMap[Txt^[Col]] = PrtNone) then
  1328.           EdComputeEffectiveColNo := Opos
  1329.         else
  1330.           EdComputeEffectiveColNo := Succ(Opos);
  1331.  
  1332.       end
  1333.     else
  1334.       EdComputeEffectiveColNo := Col;
  1335.   end;                       {EdComputeEffectiveColNo}
  1336.  
  1337.   function EdAdjustColno(P, Q : PlineDesc; Col : Integer) : Integer;
  1338.     {-Adjust returned colno so effcol(p,col)=effcol(q,col)}
  1339.   var
  1340.     EffCol, Ipos, Opos : Integer;
  1341.  
  1342.   begin                      {EdAdjustColno}
  1343.     {Get the apparent column to match}
  1344.     EffCol := EdComputeEffectiveColNo(True, Q, Col);
  1345.     {Scan the new line to see what text position corresponds to EffCol}
  1346.     with P^ do begin
  1347.       Ipos := 0;
  1348.       Opos := 0;
  1349.       while Opos < EffCol do begin
  1350.         Inc(Ipos);
  1351.         if Ipos > Bufflen then
  1352.           Inc(Opos)
  1353.         else if PrintMap[Txt^[Ipos]] = PrtNone then
  1354.           Inc(Opos);
  1355.       end;
  1356.     end;
  1357.     EdAdjustColno := Ipos;
  1358.   end;                       {EdAdjustColno}
  1359.  
  1360.   procedure EdTopScreen;
  1361.     {-Move cursor to top of screen}
  1362.   var
  1363.     P : PlineDesc;
  1364.  
  1365.   begin                      {EdTopScreen}
  1366.     with Curwin^ do begin
  1367.       P := Curline;
  1368.       Curline := TopLine;
  1369.       Lineno := 1;
  1370.       if AT then
  1371.         {Adjust current column number to match appearance of previous line}
  1372.         Colno := EdAdjustColno(Curline, P, Colno);
  1373.     end;
  1374.   end;                       {EdTopScreen}
  1375.  
  1376.   procedure EdBottomScreen;
  1377.     {-Move cursor to bottom of screen}
  1378.   var
  1379.     P : PlineDesc;
  1380.  
  1381.   begin                      {EdBottomScreen}
  1382.     with Curwin^ do begin
  1383.       P := Curline;
  1384.       Curline := TopLine;
  1385.       Lineno := 1;
  1386.       while EdPtrNotNil(Curline^.Fwdlink) and (Lineno <= Lastlineno-Firsttextno) do begin
  1387.         Inc(Lineno);
  1388.         EdFwdPtr(Curline);
  1389.       end;
  1390.       if AT then
  1391.         {Adjust current column number to match appearance of previous line}
  1392.         Colno := EdAdjustColno(Curline, P, Colno);
  1393.     end;
  1394.   end;                       {EdBottomScreen}
  1395.  
  1396.   procedure EdCompress(P : PlineDesc; Lmargin : Integer; var Col, Len : Integer);
  1397.     {-Remove excess spaces internal to a line}
  1398.   var
  1399.     Lptr, Tptr, OrigCol : Integer;
  1400.     Tline : TextLine;
  1401.     LastC, C : Char;
  1402.  
  1403.   begin                      {EdCompress}
  1404.  
  1405.     {Get length to last non-blank}
  1406.     Len := EdTextLength(P);
  1407.  
  1408.     {Save column position}
  1409.     OrigCol := Col;
  1410.  
  1411.     if Lmargin >= Len then
  1412.       {No compression will occur}
  1413.       Exit;
  1414.  
  1415.     with P^ do
  1416.       if Len > 0 then begin
  1417.  
  1418.         Lptr := 1;
  1419.  
  1420.         {Pass on leading spaces and characters left of left margin without change}
  1421.         while (Txt^[Lptr] = Blank) or (Lptr <= Lmargin) do begin
  1422.           Tline[Lptr] := Txt^[Lptr];
  1423.           Inc(Lptr);
  1424.         end;
  1425.         Tptr := Pred(Lptr);
  1426.  
  1427.         {Output non-blank characters}
  1428.         {Initialize lastc to anything but a blank}
  1429.         LastC := Period;
  1430.         while Lptr <= Len do begin
  1431.           C := Txt^[Lptr];
  1432.           if C = Blank then begin
  1433.             if (LastC <> Blank) then begin
  1434.               Inc(Tptr);
  1435.               Tline[Tptr] := C;
  1436.             end else begin
  1437.               if Lptr <= OrigCol then
  1438.                 {Don't output blank, the cursor column number is pulled one left}
  1439.                 Dec(Col);
  1440.               {Fix up markers}
  1441.               EdFixBlockInsertedSpace(P, Succ(Tptr), -1);
  1442.               EdCheckNoMarker;
  1443.               EdFixMarkInsertedSpace(P, Tptr, -1);
  1444.             end;
  1445.           end else begin
  1446.             {All non-blank characters output}
  1447.             Inc(Tptr);
  1448.             Tline[Tptr] := C;
  1449.           end;
  1450.           Inc(Lptr);
  1451.           LastC := C;
  1452.         end;
  1453.  
  1454.         {Copy back onto input}
  1455.         Move(Tline[1], Txt^[1], Tptr);
  1456.         FillChar(Txt^[Succ(Tptr)], Bufflen-Tptr, Blank);
  1457.         {Return length}
  1458.         Len := Tptr;
  1459.  
  1460.       end;
  1461.   end;                       {EdCompress}
  1462.  
  1463.   procedure EdWindowGoto(Wno : Byte);
  1464.     {-Move cursor into window Wno, counted from top of screen}
  1465.   var
  1466.     W : Pwindesc;
  1467.     Rezoom : Boolean;
  1468.  
  1469.   begin                      {EdWindowGoto}
  1470.     W := EdFindWindesc(Wno);
  1471.     Rezoom := Zoomed and (W <> Curwin);
  1472.     if Rezoom then
  1473.       EdZoomWindow(False);
  1474.     Curwin := W;
  1475.     if Rezoom then
  1476.       EdZoomWindow(False);
  1477.   end;                       {EdWindowGoto}
  1478.  
  1479.   procedure EdBlockHide;
  1480.     {-Toggle block display}
  1481.  
  1482.   begin                      {EdBlockHide}
  1483.     if Blockhide then
  1484.       {Turn off blockhide only if From and To markers form a continuous stream}
  1485.       Blockhide := EdBlockDiscontinuous
  1486.     else begin
  1487.       {Turn off block display}
  1488.       Blockhide := True;
  1489.       {Reset block flags everywhere}
  1490.       EdOffblock;
  1491.     end;
  1492.   end;                       {EdBlockHide}
  1493.  
  1494.   procedure EdFixBaseLine(WindFrom : Pwindesc);
  1495.     {-Redefine window Topline and Curline before a block operation deletes them}
  1496.   var
  1497.     W : Pwindesc;
  1498.  
  1499.   begin                      {EdFixBaseLine}
  1500.     W := WindFrom;
  1501.     repeat
  1502.       {Check all windows sharing the text stream including windfrom itself}
  1503.       if W^.Stream = WindFrom^.Stream then
  1504.         with W^ do begin
  1505.           if EdCursorInBlock(TopLine, 1, False) or (TopLine = Blockto.Line) then
  1506.             TopLine := Blockfrom.Line;
  1507.           if EdCursorInBlock(Curline, Colno, False) or (Curline = Blockto.Line) then begin
  1508.             Curline := Blockfrom.Line;
  1509.             Colno := Blockfrom.Col;
  1510.           end;
  1511.         end;
  1512.       EdFwdPtr(W);
  1513.     until (W = WindFrom);
  1514.   end;                       {EdFixBaseLine}
  1515.  
  1516.   procedure EdSetupBlock(var MarkA, MarkB : BlockMarker);
  1517.     {-Check for a contiguous block, and set marks and blockhide accordingly}
  1518.   var
  1519.     Len : Integer;
  1520.  
  1521.   begin                      {EdSetupBlock}
  1522.  
  1523.     {Turn off all lines in blocks}
  1524.     EdOffblock;
  1525.  
  1526.     {Repoint one end of the block}
  1527.     with Curwin^, MarkA do begin
  1528.       Line := Curline;
  1529.       Col := Colno;
  1530.       {Assure block stays within text buffer}
  1531.       Len := EdTextLength(Curline);
  1532.       if Col > Len then
  1533.         Col := Succ(Len);
  1534.     end;
  1535.  
  1536.     {Assure complete block defined}
  1537.     if EdPtrIsNil(MarkB.Line) then begin
  1538.       {Only one end defined}
  1539.       Blockhide := True;
  1540.       Exit;
  1541.     end;
  1542.  
  1543.     Blockhide := EdBlockDiscontinuous;
  1544.     if Blockhide then begin
  1545.       EdSetPtrNil(MarkB.Line);
  1546.       MarkB.Col := 0;
  1547.     end;
  1548.  
  1549.   end;                       {EdSetupBlock}
  1550.  
  1551.   procedure EdBlockBegin;
  1552.     {-Set block begin marker}
  1553.  
  1554.   begin                      {EdBlockBegin}
  1555.     EdSetupBlock(Blockfrom, Blockto);
  1556.   end;                       {EdBlockBegin}
  1557.  
  1558.   procedure EdBlockEnd;
  1559.     {-Set block end marker}
  1560.  
  1561.   begin                      {EdBlockEnd}
  1562.     EdSetupBlock(Blockto, Blockfrom);
  1563.   end;                       {EdBlockEnd}
  1564.  
  1565.   procedure EdBlockWord;
  1566.     {-Mark the current word as a block}
  1567.   var
  1568.     C, Len : Word;
  1569.  
  1570.   begin                      {EdBlockWord}
  1571.  
  1572.     with Curwin^ do begin
  1573.  
  1574.       Len := EdTextLength(Curline);
  1575.       if Len = 0 then
  1576.         {Line is empty, don't change anything}
  1577.         Exit;
  1578.  
  1579.       {Set marker to this line}
  1580.       Blockto.Line := Curline;
  1581.       Blockfrom.Line := Curline;
  1582.  
  1583.       C := Colno;
  1584.  
  1585.       with Curline^ do begin
  1586.  
  1587.         if C > Len then
  1588.           {Cursor past end of line, mark word to left}
  1589.           C := Len;
  1590.  
  1591.         if (Txt^[C] in Alphas) then begin
  1592.           {In a word, scan to left edge of word}
  1593.           while (C > 0) and (Txt^[C] in Alphas) do
  1594.             Dec(C);
  1595.           Inc(C);
  1596.         end else
  1597.           {In white space, scan right to next word}
  1598.           while not(Txt^[C] in Alphas) do
  1599.             Inc(C);
  1600.  
  1601.         {From marker starts at left edge of word}
  1602.         Blockfrom.Col := C;
  1603.  
  1604.         {Scan right past end of word}
  1605.         while (C <= Len) and (Txt^[C] in Alphas) do
  1606.           Inc(C);
  1607.  
  1608.         {To marker is just past right edge of word}
  1609.         Blockto.Col := C;
  1610.  
  1611.       end;
  1612.     end;
  1613.  
  1614.     EdOffblock;
  1615.     Blockhide := False;
  1616.  
  1617.   end;                       {EdBlockWord}
  1618.  
  1619.  
  1620. begin
  1621.   Nextstream := 0;           {Initialize text stream identifier}
  1622. end.
  1623.