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

  1. {                          EDMEMOP.PAS
  2.                              ED 4.0
  3.              Copyright (c) 1985, 87 by Borland International, Inc.            }
  4.  
  5. {$I eddirect.inc}
  6.  
  7. unit EdMemOp;
  8.   {-Allocate and deallocate memory for text lines and windows}
  9.  
  10. interface
  11.  
  12. uses
  13.   crt,                       {Basic video}
  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, prompt and error interactions}
  24.  
  25. var
  26.   ExactAllocation : Boolean; {Set true to allocate buffers of same size as text}
  27.  
  28. function EdBufferSize(Ncols : Integer) : Integer;
  29.   {-Return a proper buffer size for the number of text columns requested}
  30.  
  31. procedure EdDesTextDesc(P : PlineDesc);
  32.   {-Destroy text descriptor}
  33.  
  34. procedure EdPushUndo(var P : PlineDesc);
  35.   {-Save a deleted line on the undo stack if possible}
  36.  
  37. procedure EdDeleteAllText(W : PwinDesc);
  38.   {-delete the entire text stream of a window}
  39.  
  40. function EdMaktextdesc(Ncols : Integer) : PlineDesc;
  41.   {-Make new text descriptor record}
  42.  
  43. function EdSizeline(P : PlineDesc; Ncols : Integer; Init : Boolean) : Boolean;
  44.   {-Expand line size to accommodate Ncols characters}
  45.  
  46. function EdAllocateWindow(Top, Len, Cr, Cc : Integer; Fn : Filepath) : PwinDesc;
  47.   {-Return a pointer to a window structure}
  48.  
  49. procedure EdJoinLinePrimitive(P : PlineDesc; LenP : Integer);
  50.   {-Join the line p at column lenP with the line following it}
  51.  
  52. procedure EdJoinline;
  53.   {-Join two lines and fix up block markers}
  54.  
  55. procedure EdInsertLinePrimitive(M : BlockMarker; var P : PlineDesc);
  56.   {-Insert a new line after marker m, return pointer to new line}
  57.  
  58. function EdInsertSpace(P : PlineDesc; Start : Integer; Num : Integer) : Boolean;
  59.   {-Insert num spaces at position start of line p}
  60.  
  61. procedure EdNewLinePrimitive;
  62.   {-Insert a new line, straighten out indents and markers}
  63.  
  64. procedure EdWindowCreate(Wno : Byte);
  65.   {-Create new window by splitting window wno in two}
  66.  
  67. procedure EdPushWindowStack(W : PwinDesc);
  68.   {-Put a window descriptor on the window free list}
  69.  
  70. procedure EdWindowDelete(Wno : Byte);
  71.   {-Perform delete window command processing}
  72.  
  73. function EdCalcMemory : VarString;
  74.   {-Return the bytes of available heap space, in a string}
  75.  
  76.   {==========================================================================}
  77.  
  78. implementation
  79.  
  80.   function EdBufferSize(Ncols : Integer) : Integer;
  81.     {-Return a proper buffer size for the number of text columns requested}
  82.  
  83.   begin                      {EdBufferSize}
  84.     if ExactAllocation then
  85.       EdBufferSize := Succ(Ncols)
  86.     else
  87.       EdBufferSize := Succ(Ncols shr 3) shl 3;
  88.   end;                       {EdBufferSize}
  89.  
  90.   procedure EdDesTextDesc(P : PlineDesc);
  91.     {-Destroy text descriptor}
  92.  
  93.   begin                      {EdDesTextdesc}
  94.     {Free text line first}
  95.     FreeMem(P^.Txt, Succ(P^.Bufflen));
  96.     {Now the linedesc itself}
  97.     FreeMem(P, SizeOf(LineDesc));
  98.   end;                       {EdDesTextdesc}
  99.  
  100.   procedure EdPushUndo(var P : PlineDesc);
  101.     {-Save a deleted line on the undo stack if possible}
  102.   var
  103.     Q : PlineDesc;
  104.     M : Integer;
  105.  
  106.   begin                      {EdPushUndo}
  107.  
  108.     {Make sure the undo stack hasn't overflowed}
  109.     if UndoLimit <> 0 then
  110.       while (UndoCount >= UndoLimit) do begin
  111.         {If we need to delete a line at the rear}
  112.         Dec(UndoCount);
  113.         Q := UndoEnd^.Backlink;
  114.         EdDesTextDesc(UndoEnd);
  115.         UndoEnd := Q;
  116.         if EdPtrIsNil(UndoEnd) then begin
  117.           UndoCount := 0;
  118.           EdSetPtrNil(UndoStack);
  119.         end else
  120.           EdSetPtrNil(UndoEnd^.FwdLink);
  121.       end;
  122.  
  123.     {Reset text markers}
  124.     if EdFlagSet(P, InMark) then
  125.       for M := 0 to MaxMarker do
  126.         with Marker[M] do
  127.           if Line = P then
  128.             EdSetPtrNil(Line);
  129.  
  130.     {Push line onto undo stack}
  131.     if UndoLimit = 0 then
  132.       {If undo is not enabled, destroy line}
  133.       EdDesTextDesc(P)
  134.     else if EdPtrIsNil(UndoStack) then begin
  135.       {No lines on the undo stack}
  136.       UndoStack := P;
  137.       UndoEnd := P;
  138.       EdSetPtrNil(P^.FwdLink);
  139.       EdSetPtrNil(P^.Backlink);
  140.       UndoCount := 1;
  141.     end else begin
  142.       {Just push the line}
  143.       EdSetPtrNil(P^.Backlink);
  144.       P^.FwdLink := UndoStack;
  145.       if EdPtrNotNil(P^.FwdLink) then
  146.         P^.FwdLink^.Backlink := P;
  147.       UndoStack := P;
  148.       Inc(UndoCount);
  149.     end;
  150.   end;                       {EdPushUndo}
  151.  
  152.   procedure EdDeleteAllText(W : PwinDesc);
  153.     {-delete the entire text stream of a window}
  154.   var
  155.     P, Q : PlineDesc;
  156.     M : Integer;
  157.  
  158.   begin                      {EdDeleteAllText}
  159.     with W^ do begin
  160.  
  161.       {Find top of the text stream}
  162.       P := TopLine;
  163.       while EdPtrNotNil(P^.Backlink) do
  164.         EdBackPtr(P);
  165.  
  166.       {Delete each line in the stream}
  167.       while EdPtrNotNil(P) do begin
  168.         Q := P;
  169.         EdFwdPtr(P);
  170.         if (Q = Blockfrom.Line) or (Q = Blockto.Line) then begin
  171.           {Reset block markers if destroyed}
  172.           EdSetPtrNil(Blockfrom.Line);
  173.           EdSetPtrNil(Blockto.Line);
  174.           Blockhide := True;
  175.         end;
  176.         if EdFlagSet(Q, InMark) then
  177.           {Reset text markers if destroyed}
  178.           for M := 0 to MaxMarker do
  179.             with Marker[M] do
  180.               if Line = Q then
  181.                 EdSetPtrNil(Line);
  182.         EdDesTextDesc(Q);
  183.       end;
  184.  
  185.       {Indicate that top line points to no text}
  186.       EdSetPtrNil(TopLine);
  187.  
  188.     end;
  189.   end;                       {EdDeleteAllText}
  190.  
  191.   {***}
  192.   function EdMaktextdesc(Ncols : Integer) : PlineDesc;
  193.     {-Make new text descriptor record}
  194.   var
  195.     Len : Integer;
  196.     P : PlineDesc;
  197.  
  198.   begin                      {EdMaktextdesc}
  199.  
  200.     if Ncols > MaxLineLength then begin
  201.       {Line too long}
  202.       EdErrormsg(41);
  203.       EdMaktextdesc := nil;
  204.       Exit;
  205.     end;
  206.  
  207.     {Calculate appropriate length of text buffer}
  208.     Len := EdBufferSize(Ncols);
  209.  
  210.     if not(EdMemAvail(Len+SizeOf(LineDesc), FreeListSpace)) then begin
  211.       EdErrormsg(35);
  212.       EdMaktextdesc := nil;
  213.       Exit;
  214.     end;
  215.  
  216.     {Get linedesc first}
  217.     GetMem(P, SizeOf(LineDesc));
  218.  
  219.     with P^ do begin
  220.       {Now get the text buffer}
  221.       GetMem(Txt, Len);
  222.  
  223.       {Don't include font descriptor byte in size of text buffer}
  224.       Bufflen := Pred(Len);
  225.  
  226.       {Fill line with blanks and initialize flags}
  227.       FillChar(Txt^, Len, Blank);
  228.       Flags := 0;
  229.     end;
  230.  
  231.     EdMaktextdesc := P;
  232.  
  233.   end;                       {EdMaktextdesc}
  234.  
  235.   function EdSizeline(P : PlineDesc; Ncols : Integer; Init : Boolean) : Boolean;
  236.     {-Expand line size to accommodate Ncols characters}
  237.   var
  238.     Q : PtextLine;
  239.     Len, PbuffLen : Integer;
  240.  
  241.   begin                      {EdSizeline}
  242.  
  243.     PbuffLen := P^.Bufflen;
  244.  
  245.     if PbuffLen > Ncols then begin
  246.       {Get out quickly -- line is long enough}
  247.       EdSizeline := True;
  248.       Exit;
  249.     end;
  250.  
  251.     if Ncols > MaxLineLength then begin
  252.       {Line too long}
  253.       EdErrormsg(41);
  254.       EdSizeline := False;
  255.       Exit;
  256.     end;
  257.  
  258.     {Calculate appropriate length of text buffer}
  259.     Len := EdBufferSize(Ncols);
  260.  
  261.     if not(EdMemAvail(Len, FreeListSpace)) then begin
  262.       EdErrormsg(35);
  263.       EdSizeline := False;
  264.       Exit;
  265.     end;
  266.  
  267.     {Get a new larger text buffer}
  268.     GetMem(Q, Len);
  269.     if Init then begin
  270.       {Copy text and font descriptor}
  271.       Move(P^.Txt^, Q^, Succ(PbuffLen));
  272.       {Blank out rest of line}
  273.       FillChar(Q^[Succ(PbuffLen)], Pred(Len-PbuffLen), Blank);
  274.     end;
  275.     {Get rid of old line buffer}
  276.     FreeMem(P^.Txt, Succ(PbuffLen));
  277.     {Attach new text buffer to line descriptor}
  278.     P^.Txt := Q;
  279.     {Don't include length byte in size}
  280.     P^.Bufflen := Pred(Len);
  281.  
  282.     EdSizeline := True;
  283.   end;                       {EdSizeline}
  284.  
  285.   function EdNewTextStream(W : PwinDesc) : Boolean;
  286.     {-Create a new text stream, returning true if successful}
  287.  
  288.   begin                      {EdNewTextStream}
  289.     EdNewTextStream := False;
  290.     with W^ do begin
  291.       TopLine := EdMaktextdesc(1);
  292.       if EdPtrIsNil(TopLine) then
  293.         Exit;
  294.       CurLine := TopLine;
  295.       LineNo := 1;
  296.       ColNo := 1;
  297.       EdSetPtrNil(TopLine^.FwdLink);
  298.       EdSetPtrNil(TopLine^.Backlink);
  299.       Stream := EdNewstream;
  300.     end;
  301.     EdNewTextStream := True;
  302.   end;                       {EdNewTextStream}
  303.  
  304.   function EdAllocateWindow(Top, Len, Cr, Cc : Integer; Fn : Filepath) : PwinDesc;
  305.     {-Return a pointer to a window structure}
  306.   var
  307.     W : PwinDesc;
  308.  
  309.   begin                      {EdAllocateWindow}
  310.     {Pop a window off the free list}
  311.     W := WinStack;
  312.     if EdNewTextStream(W) then begin
  313.       EdFwdPtr(WinStack);
  314.       {Initialize window settings}
  315.       EdInitWindowSettings(W);
  316.       with W^ do begin
  317.         EdSetPtrNil(FwdLink);
  318.         EdSetPtrNil(Backlink);
  319.         Filename := Fn;
  320.         FirstLineNo := Top;
  321.         LastLineNo := Pred(Top+Len);
  322.         LineNo := Cr;
  323.         ColNo := Cc;
  324.       end;
  325.       EdSetTextNo(W);
  326.       EdAllocateWindow := W;
  327.     end else
  328.       EdAllocateWindow := nil;
  329.   end;                       {EdAllocateWindow}
  330.  
  331.   procedure EdJoinLinePrimitive(P : PlineDesc; LenP : Integer);
  332.     {-Join the line p at column lenP with the line following it}
  333.   var
  334.     LenQ, M : Integer;
  335.     Q : PlineDesc;
  336.  
  337.   begin                      {EdJoinLinePrimitive}
  338.  
  339.     Q := P^.FwdLink;
  340.     if EdPtrIsNil(Q) then
  341.       Exit;
  342.  
  343.     {Get length of the next line}
  344.     LenQ := EdTextLength(Q);
  345.  
  346.     {Size up this line to hold the next}
  347.     if not(EdSizeline(P, LenP+LenQ, True)) then
  348.       Exit;
  349.  
  350.     {Fix up Text Markers}
  351.     if EdFlagSet(Q, InMark) then
  352.       for M := 0 to MaxMarker do
  353.         with Marker[M] do
  354.           if Line = Q then begin
  355.             Col := Col+LenP;
  356.             Line := P;
  357.             EdSetFlag(P, InMark);
  358.           end;
  359.  
  360.     {Move the text of the next into this one}
  361.     if LenQ > 0 then
  362.       Move(Q^.Txt^[1], P^.Txt^[Succ(LenP)], LenQ);
  363.  
  364.     {Disconnect the next line}
  365.     P^.FwdLink := Q^.FwdLink;
  366.     if EdPtrNotNil(P^.FwdLink) then
  367.       P^.FwdLink^.Backlink := P;
  368.  
  369.     {Deallocate its space}
  370.     EdDesTextDesc(Q);
  371.  
  372.   end;                       {EdJoinlineprimitive}
  373.  
  374.   procedure EdJoinline;
  375.     {-Join two lines and fix up block markers}
  376.   var
  377.     P, Q : PlineDesc;
  378.     C : Integer;
  379.  
  380.   begin                      {EdJoinline}
  381.     with CurWin^ do begin
  382.  
  383.       P := CurLine;
  384.       Q := CurLine^.FwdLink;
  385.       C := Pred(ColNo);
  386.  
  387.       if EdPtrNotNil(Q) then begin
  388.  
  389.         {Fix up block markers}
  390.         if Q = Blockfrom.Line then begin
  391.           Blockfrom.Col := Blockfrom.Col+C;
  392.           Blockfrom.Line := P;
  393.           if not(Blockhide) then
  394.             EdSetFlag(P, InBlock);
  395.         end;
  396.         if Q = Blockto.Line then begin
  397.           Blockto.Col := Blockto.Col+C;
  398.           Blockto.Line := P;
  399.         end;
  400.  
  401.         {Correct any windows whose topline, curline or lineno relate to q}
  402.         EdFixUpWindowSpan(Q);
  403.  
  404.         {Attach the next line to this one}
  405.         EdJoinLinePrimitive(P, C);
  406.  
  407.       end;
  408.     end;
  409.   end;                       {EdJoinline}
  410.  
  411.   procedure EdInsertLinePrimitive(M : BlockMarker; var P : PlineDesc);
  412.     {-Insert a new line after marker m, return pointer to new line}
  413.   var
  414.     Llen, Len : Integer;
  415.  
  416.   begin                      {EdInsertLinePrimitive}
  417.     with M do begin
  418.  
  419.       {Number of characters to copy from current line to new line}
  420.       Llen := EdTextLength(Line);
  421.       if Llen < Pred(Col) then
  422.         Len := 0
  423.       else
  424.         Len := Llen-Pred(Col);
  425.  
  426.       {Get a new buffer big enough to hold what's needed}
  427.       P := EdMaktextdesc(Len);
  428.       if EdPtrIsNil(P) then
  429.         Exit;
  430.  
  431.       {Attach the new buffer after the specified line}
  432.       EdLinkbuffer(Line, P);
  433.  
  434.       {Now split the text}
  435.       if Len > 0 then begin
  436.         Move(Line^.Txt^[Col], P^.Txt^[1], Len);
  437.         FillChar(Line^.Txt^[Col], Len, Blank)
  438.       end;
  439.  
  440.       {Fix up text markers}
  441.       if EdFlagSet(Line, InMark) then
  442.         EdFixMarkInsertedLine(Line, P, Col, Col);
  443.  
  444.     end;
  445.   end;                       {EdInsertLinePrimitive}
  446.  
  447.   function EdInsertSpace(P : PlineDesc; Start : Integer; Num : Integer) : Boolean;
  448.     {-Insert num spaces at position start of line p}
  449.   var
  450.     Len, NewLen : Integer;
  451.  
  452.   begin                      {EdInsertSpace}
  453.  
  454.     Len := EdTextLength(P);
  455.     if Start > Len then
  456.       NewLen := Succ(Start+Num)
  457.     else
  458.       NewLen := Succ(Len+Num);
  459.  
  460.     {Size up the line}
  461.     if not EdSizeline(P, NewLen, True) then begin
  462.       EdInsertSpace := False;
  463.       Exit;
  464.     end;
  465.  
  466.     {Move the text over and fill with blanks}
  467.     with P^ do begin
  468.       if Start <= Len then
  469.         Move(Txt^[Start], Txt^[Start+Num], Succ(Len-Start));
  470.       FillChar(Txt^[Start], Num, Blank);
  471.     end;
  472.  
  473.     {Fix up markers}
  474.     EdFixMarkInsertedSpace(P, Start, Num);
  475.     EdFixBlockInsertedSpace(P, Start, Num);
  476.  
  477.     EdInsertSpace := True;
  478.  
  479.   end;                       {EdInsertSpace}
  480.  
  481.   {***}
  482.   procedure EdNewLinePrimitive;
  483.     {-Insert a new line, straighten out indents and markers}
  484.   var
  485.     P : PlineDesc;
  486.     Ind, InsCount, SaveCol : Integer;
  487.     M : BlockMarker;
  488.  
  489.   begin                      {EdNewLinePrimitive}
  490.     with CurWin^ do begin
  491.  
  492.       M.Line := CurLine;
  493.       M.Col := ColNo;
  494.  
  495.       {Insert new line after current}
  496.       EdInsertLinePrimitive(M, P);
  497.       if EdPtrIsNil(P) then
  498.         Exit;
  499.  
  500.       SaveCol := ColNo;
  501.       InsCount := 0;
  502.       P := CurLine;
  503.  
  504.       {Move to beginning of new line}
  505.       EdFwdPtr(CurLine);
  506.       ColNo := 1;
  507.  
  508.       if AI then begin
  509.         {Autoindent mode}
  510.  
  511.         if AI then
  512.           {Get leading spaces from previous line}
  513.           Ind := EdLineIndent(P)
  514.         else
  515.           Ind := 1;
  516.  
  517.         if Ind > 1 then begin
  518.           {Insert spaces at start of curline}
  519.           InsCount := Pred(Ind);
  520.           if not(EdInsertSpace(CurLine, 1, InsCount)) then
  521.             Exit;
  522.           ColNo := Ind;
  523.         end;
  524.       end;
  525.  
  526.       {Fix up block markers}
  527.       EdFixBlockInsertedLine(P, CurLine, SaveCol, Pred(SaveCol-InsCount));
  528.  
  529.       Modified := True;
  530.  
  531.       {Guarantee a complete screen update}
  532.       IntrFlag := NoInterr;
  533.  
  534.     end;
  535.   end;                       {EdNewLinePrimitive}
  536.  
  537.   procedure EdWindowCreate(Wno : Byte);
  538.     {-Create new window by splitting window wno in two}
  539.   var
  540.     W, V : PwinDesc;
  541.     CurrentSize, Size : Byte;
  542.  
  543.   begin                      {EdWindowCreate}
  544.  
  545.     {Get a pointer to the window to divide and compute the sizes}
  546.     W := EdFindWindesc(Wno);
  547.     with W^ do
  548.       CurrentSize := Succ(LastLineNo-FirstLineNo);
  549.     Size := CurrentSize shr 1;
  550.  
  551.     if (Size <= MinWindowLines) then begin
  552.       {New window too small}
  553.       EdErrormsg(22);
  554.       Exit;
  555.     end;
  556.  
  557.     if (CurrentSize-Size) <= MinWindowLines then begin
  558.       {Not enough space left to fit on screen}
  559.       EdErrormsg(120);
  560.       Exit;
  561.     end;
  562.  
  563.     {Make a new window structure}
  564.     V := EdAllocateWindow(Succ(W^.LastLineNo-Size), Size, Line1, Col1, NoFile);
  565.  
  566.     if EdPtrIsNil(V) then
  567.       {No memory for another window, error already displayed}
  568.       Exit;
  569.  
  570.     {Compress existing window}
  571.     W^.LastLineNo := W^.LastLineNo-Size;
  572.  
  573.     {We may be positioned outside the window's area now}
  574.     EdBackupCurline(W);
  575.  
  576.     {New window is linked AFTER wno in the display list}
  577.     V^.Backlink := W;
  578.     V^.FwdLink := W^.FwdLink;
  579.     W^.FwdLink^.Backlink := V;
  580.     W^.FwdLink := V;
  581.  
  582.   end;                       {EdWindowCreate}
  583.  
  584.   procedure EdPushWindowStack(W : PwinDesc);
  585.     {-Put a window descriptor on the window free list}
  586.  
  587.   begin                      {EdPushWindowStack}
  588.     W^.FwdLink^.Backlink := W^.Backlink;
  589.     W^.Backlink^.FwdLink := W^.FwdLink;
  590.     W^.FwdLink := WinStack;
  591.     WinStack := W;
  592.   end;                       {EdPushWindowStack}
  593.  
  594.   procedure EdWindowDelete(Wno : Byte);
  595.     {-Perform delete window command processing}
  596.   var
  597.     W : PwinDesc;
  598.  
  599.   begin                      {EdWindowDelete}
  600.  
  601.     {Find window descriptor}
  602.     W := EdFindWindesc(Wno);
  603.  
  604.     if W = Window1 then begin
  605.  
  606.       {Window below gets the lines}
  607.       EdFwdPtr(Window1);
  608.       if CurWin = W then
  609.         CurWin := Window1;
  610.       Window1^.FirstLineNo := W^.FirstLineNo;
  611.       EdSetTextNo(Window1);
  612.  
  613.     end else begin
  614.  
  615.       {Window above gets the lines}
  616.       if CurWin = W then
  617.         CurWin := W^.Backlink;
  618.       W^.Backlink^.LastLineNo := W^.LastLineNo;
  619.  
  620.     end;
  621.  
  622.     {If no other object references the text stream, it may be deleted}
  623.     if not(EdLinkedWindow(W)) then
  624.       EdDeleteAllText(W);
  625.  
  626.     {Push window onto free list}
  627.     EdPushWindowStack(W);
  628.  
  629.   end;                       {EdWindowDelete}
  630.  
  631.   function EdCalcMemory : VarString;
  632.     {-Return the bytes of available heap space, in a string}
  633.   var
  634.     S : VarString;
  635.  
  636.   begin                      {EdCalcMemory}
  637.     Str(MemAvail, S);
  638.     EdCalcMemory := Blank+S+EdGetMessage(328);
  639.   end;                       {EdCalcMemory}
  640.  
  641. begin
  642.   {Use ExactAllocation only during file reads}
  643.   ExactAllocation := False;
  644.  
  645.   {Allocate current line buffer}
  646.   CurLineBuf := EdMaktextdesc(MaxLineLength);
  647.   CurLineCol := 1;
  648. end.
  649.