home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / ftes46b5.zip / ftes46b5 / src / e_block.cpp < prev    next >
C/C++ Source or Header  |  1998-01-26  |  28KB  |  1,067 lines

  1. /*    e_block.cpp
  2.  *
  3.  *    Copyright (c) 1994-1996, Marko Macek
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  */
  9.  
  10. #include "fte.h"
  11.  
  12. ///////////////////////////////////////////////////////////////////////////////
  13. // Block Commands                                                            //
  14. ///////////////////////////////////////////////////////////////////////////////
  15.  
  16. int EBuffer::SetBB(EPoint M) {
  17.     EPoint OldBB = BB;
  18.     int MinL, MaxL;
  19.     
  20.     if (BB.Row == M.Row && BB.Col == M.Col) return 1;
  21. #ifdef CONFIG_UNDOREDO
  22.     if (PushBlockData() == 0) return 0;
  23. #endif
  24.     BB = M;
  25.     if (OldBB.Row == -1) OldBB = BE;
  26.     if ((OldBB.Col != BB.Col) && (BlockMode == bmColumn)) BlockRedraw();
  27.     MinL = Min(OldBB.Row, BB.Row);
  28.     MaxL = Max(OldBB.Row, BB.Row);
  29.     if (MinL != -1)
  30.         if (MinL <= MaxL) Draw(MinL, MaxL);
  31.     return 1;
  32. }
  33.  
  34. int EBuffer::SetBE(EPoint M) {
  35.     EPoint OldBE = BE;
  36.     int MinL, MaxL;
  37.   
  38.     if (BE.Row == M.Row && BE.Col == M.Col) return 1;
  39. #ifdef CONFIG_UNDOREDO
  40.     if (PushBlockData() == 0) return 0;
  41. #endif
  42.     BE = M;
  43.     if (OldBE.Row == -1) OldBE = BB;
  44.     if ((OldBE.Col != BE.Col) && (BlockMode == bmColumn)) BlockRedraw();
  45.     MinL = Min(OldBE.Row, BE.Row);
  46.     MaxL = Max(OldBE.Row, BE.Row);
  47.     if (MinL != -1)
  48.         if (MinL <= MaxL) Draw(MinL, MaxL);
  49.     return 1;
  50. }
  51.  
  52. int EBuffer::CheckBlock() {
  53.     if (BB.Row == -1 && BE.Row == 1) {
  54.         BB.Col = -1;
  55.         BE.Col = -1;
  56.         return 0;
  57.     }
  58.     if (BB.Row == -1 || BE.Row == -1) return 0;
  59.     if (BB.Row >= RCount) BB.Row = RCount - 1;
  60.     if (BE.Row >= RCount) BE.Row = RCount - 1;
  61.     switch(BlockMode) {
  62.     case bmLine:
  63.         BB.Col = 0;
  64.         BE.Col = 0;
  65.         if (BB.Row >= BE.Row) return 0;
  66.         break;
  67.     case bmColumn:
  68.         if (BB.Col >= BE.Col) return 0;
  69.         if (BB.Row >= BE.Row) return 0;
  70.         break;
  71.     case bmStream:
  72.         if (BB.Row > BE.Row) return 0;
  73.         if (BB.Row == BE.Row && BB.Col >= BE.Col) return 0;
  74.         break;
  75.     }
  76.     return 1;
  77. }
  78.  
  79. int EBuffer::BlockRedraw() {
  80.     if (BB.Row == -1 || BE.Row == -1) return 0;
  81.     Draw(BB.Row, BE.Row);
  82.     return 1;
  83. }
  84.  
  85.  
  86. int EBuffer::BlockBegin() {
  87.     EPoint X;
  88.     
  89.     X.Row = VToR(CP.Row);
  90.     X.Col = CP.Col;
  91.     CheckBlock();
  92.     SetBB(X);
  93.     return 1;
  94. }
  95.  
  96. int EBuffer::BlockEnd() {
  97.     EPoint X;
  98.     
  99.     X.Row = VToR(CP.Row);
  100.     X.Col = CP.Col;
  101.     CheckBlock();
  102.     SetBE(X);
  103.     return 1;
  104. }
  105.  
  106. int EBuffer::BlockUnmark() {
  107.     EPoint Null(-1,-1);
  108.     
  109.     SetBB(BE);
  110.     SetBE(Null);
  111.     SetBB(Null);
  112.     AutoExtend = 0;
  113.     return 1;
  114. }
  115.  
  116. int EBuffer::BlockCut(int Append) {
  117.     if (BlockCopy(Append) && BlockKill()) return 1;
  118.     return 0;
  119. }
  120.  
  121. int EBuffer::BlockCopy(int Append) {
  122.     EPoint B, E;
  123.     int L;
  124.     int SL, OldCount;
  125.     
  126.     AutoExtend = 0;
  127.     if (CheckBlock() == 0) return 0;
  128.     if (RCount == 0) return 0;
  129.     if (SS == 0) return 0;
  130.     if (Append) {
  131.         if (SystemClipboard)
  132.             GetPMClip();
  133.     } else
  134.         SS->Clear();
  135.     SS->BlockMode = BlockMode;
  136.     BFI(SS, BFI_TabSize) = BFI(this, BFI_TabSize);
  137.     BFI(SS, BFI_ExpandTabs) = BFI(this, BFI_ExpandTabs);
  138.     BFI(SS, BFI_Undo) = 0;
  139.     B = BB;
  140.     E = BE;
  141.     OldCount = SL = SS->RCount;
  142.     switch (BlockMode) {
  143.     case bmLine:
  144.         for (L = B.Row; L < E.Row; L++) {
  145.             if (SS->InsLine(SL, 0) == 0) return 0;
  146.             if (SS->InsLineText(SL, 0, -1, 0, RLine(L)) == 0) return 0;
  147.             SL++;
  148.         }
  149.         break;
  150.         
  151.     case bmColumn:
  152.         for (L = B.Row; L < E.Row; L++) {
  153.             if (SS->InsLine(SL, 0) == 0) return 0;
  154.             if (SS->InsLineText(SL, 0, E.Col - B.Col, B.Col, RLine(L)) == 0) return 0;
  155.             if (SS->PadLine(SL, E.Col - B.Col) == 0) return 0;
  156.             SL++;
  157.         }
  158.         break;
  159.         
  160.     case bmStream:
  161.         if (B.Row == E.Row) {
  162.             if (SS->InsLine(SL, 0) == 0) return 0;
  163.             if (SS->InsLineText(SL, 0, E.Col - B.Col, B.Col, RLine(B.Row)) == 0) return 0;
  164.         } else {
  165.             if (SS->InsLine(SL, 0) == 0) return 0;
  166.             if (SS->InsLineText(SL, 0, -1, B.Col, RLine(B.Row)) == 0) return 0;
  167.             SL++;
  168.             for (L = B.Row + 1; L < E.Row; L++) {
  169.                 if (SS->InsLine(SL, 0) == 0) return 0;
  170.                 if (SS->InsLineText(SL, 0, -1, 0, RLine(L)) == 0) return 0;
  171.                 SL++;
  172.             }
  173.             if (SS->InsLine(SL, 0) == 0) return 0;
  174.             if (SS->InsLineText(SL, 0, E.Col, 0, RLine(E.Row)) == 0) return 0;
  175.         }
  176.         if (Append && OldCount > 0)
  177.             if (SS->JoinLine(OldCount - 1, 0) == 0)
  178.                 return 0;
  179.         break;
  180.     }
  181.     if (SystemClipboard)
  182.     PutPMClip();
  183.     return 1;
  184. }
  185.  
  186. int EBuffer::BlockPasteStream() {
  187.     BlockMode = bmStream;
  188.     return BlockPaste();
  189. }
  190.  
  191. int EBuffer::BlockPasteLine() {
  192.     BlockMode = bmLine;
  193.     return BlockPaste();
  194. }
  195.  
  196. int EBuffer::BlockPasteColumn() {
  197.     BlockMode = bmColumn;
  198.     return BlockPaste();
  199. }
  200.  
  201. int EBuffer::BlockPaste() {
  202.     EPoint B, E;
  203.     int L, BL;
  204.     
  205.     if (SystemClipboard)
  206.     GetPMClip();
  207.  
  208.     if (SS == 0) return 0;
  209.     if (SS->RCount == 0) return 0;
  210.     AutoExtend = 0;
  211.     BFI(SS, BFI_TabSize) = BFI(this, BFI_TabSize);
  212.     BFI(SS, BFI_ExpandTabs) = BFI(this, BFI_ExpandTabs);
  213.     BFI(SS, BFI_Undo) = 0;
  214.     BlockUnmark();
  215.     B.Row = VToR(CP.Row);
  216.     B.Col = CP.Col;
  217.     BL = B.Row;
  218.     switch(BlockMode) {
  219.     case bmLine:
  220.         B.Col = 0;
  221.         for (L = 0; L < SS->RCount; L++) {
  222.             if (InsLine(BL, 0) == 0) return 0;
  223.             if (InsLineText(BL, 0, SS->LineLen(L), 0, SS->RLine(L)) == 0) return 0;
  224.             BL++;
  225.         }
  226.         E.Row = BL;
  227.         E.Col = 0;
  228.         SetBB(B);
  229.         SetBE(E);
  230.         break;
  231.     
  232.     case bmColumn:
  233.         for (L = 0; L < SS->RCount; L++) {
  234.             if (AssertLine(BL) == 0) return 0;
  235.             if (InsLineText(BL, B.Col, SS->LineLen(L), 0, SS->RLine(L)) == 0) return 0;
  236.         if (TrimLine(BL) == 0) return 0;
  237.             BL++;
  238.         }
  239.         if (AssertLine(BL) == 0) return 0;
  240.         E.Row = BL;
  241.         E.Col = B.Col + SS->LineLen(0);
  242.         SetBB(B);
  243.         SetBE(E);
  244.         break;
  245.     
  246.     case bmStream:
  247.         if (SS->RCount > 1)
  248.             if (SplitLine(B.Row, B.Col) == 0) return 0;
  249.         if (InsLineText(B.Row, B.Col, SS->LineLen(0), 0, SS->RLine(0)) == 0) return 0;
  250.         E = B;
  251.         E.Col += SS->LineLen(0);
  252.         BL++;
  253.         if (SS->RCount > 1) {
  254.             for (L = 1; L < SS->RCount - 1; L++) {
  255.                 if (InsLine(BL, 0) == 0) return 0;
  256.                 if (InsLineText(BL, 0, SS->LineLen(L), 0, SS->RLine(L)) == 0) return 0;
  257.                 BL++;
  258.             }
  259.             L = SS->RCount - 1;
  260.             if (InsLineText(BL, 0, SS->LineLen(L), 0, SS->RLine(L)) == 0) return 0;
  261.             E.Col = SS->LineLen(L);
  262.             E.Row = BL;
  263.         }
  264.         SetBB(B);
  265.         SetBE(E);
  266.         break;
  267.     }
  268.     return 1;    
  269. }
  270.  
  271. int EBuffer::BlockKill() {
  272.     EPoint B, E;
  273.     int L;
  274.     int Y = -1;
  275.     
  276.     AutoExtend = 0;
  277.     if (CheckBlock() == 0) return 0;
  278.     if (RCount <= 0) return 0;
  279.     B = BB;
  280.     E = BE;
  281.     Draw(B.Row, -1);
  282. //    if (MoveToPos(B.Col, B.Row) == 0) return 0;
  283.  
  284. #ifdef CONFIG_UNDOREDO
  285.     if (BFI(this, BFI_Undo) == 1) {
  286.         if (PushULong(CP.Col) == 0) return 0;
  287.         if (PushULong(CP.Row) == 0) return 0;
  288.         if (PushUChar(ucPosition) == 0) return 0;
  289.     }
  290. #endif
  291.     
  292.     switch (BlockMode) {
  293.     case bmLine:
  294.         Y = VToR(CP.Row);
  295.         if (Y >= B.Row) {
  296.             if (Y >= E.Row) {
  297.                 if (SetPosR(CP.Col, Y - (E.Row - B.Row)) == 0) return 0;
  298.             } else {
  299.                 if (SetPosR(CP.Col, B.Row) == 0) return 0;
  300.             }
  301.         }
  302.         for (L = B.Row; L < E.Row; L++)
  303.             if (DelLine(B.Row) == 0) return 0;
  304.         break;
  305.         
  306.     case bmColumn:
  307.         Y = VToR(CP.Row);
  308.         if (Y >= B.Row && Y < E.Row) {
  309.             if (CP.Col >= B.Col) {
  310.                 if (CP.Col >= E.Col) {
  311.                     if (SetPos(CP.Col - (E.Col - B.Col), CP.Row) == 0) return 0;
  312.                 } else {
  313.                     if (SetPos(B.Col, CP.Row) == 0) return 0;
  314.                 }
  315.             }
  316.         }
  317.         for (L = B.Row; L < E.Row; L++)
  318.             if (DelText(L, B.Col, E.Col - B.Col) == 0) return 0;
  319.         break;
  320.         
  321.     case bmStream:
  322.         Y = VToR(CP.Row);
  323.         
  324.         if (B.Row == E.Row) {
  325.             if (Y == B.Row) {
  326.                 if (CP.Col >= B.Col) {
  327.                     if (CP.Col >= E.Col) {
  328.                         if (SetPos(CP.Col - (E.Col - B.Col), CP.Row) == 0) return 0;
  329.                     } else {
  330.                         if (SetPos(B.Col, CP.Row) == 0) return 0;
  331.                     }
  332.                 }
  333.             }
  334.             if (DelText(B.Row, B.Col, E.Col - B.Col) == 0) return 0;
  335.         } else {
  336.             if (Y >= B.Row) {
  337.                 if (Y > E.Row || (Y == E.Row && E.Col == 0)) {
  338.                     if (SetPosR(CP.Col, Y - (E.Row - B.Row)) == 0) return 0;
  339.                 } else if (Y == E.Row) {
  340.                     if (CP.Col >= E.Col) {
  341.                         if (SetPosR(CP.Col - E.Col + B.Col, B.Row) == 0) return 0;
  342.                     } else {
  343.                         if (SetPosR(B.Col, B.Row) == 0) return 0;
  344.                     }
  345.                 } else {
  346.                     if (SetPosR(B.Col, B.Row) == 0) return 0;
  347.                 }
  348.             }
  349.             if (DelText(E.Row, 0, E.Col) == 0) return 0;
  350.             for (L = B.Row + 1; L < E.Row; L++)
  351.                 if (DelLine(B.Row + 1) == 0) return 0;
  352.             if (DelText(B.Row, B.Col, -1) == 0) return 0;
  353.             if (JoinLine(B.Row, B.Col) == 0) return 0;
  354.         }
  355.         break;
  356.     }
  357.     return BlockUnmark();
  358. }
  359.  
  360. int EBuffer::ClipClear() {
  361.     if (SS == 0)
  362.         return 0;
  363.     SS->Clear();
  364.     if (SystemClipboard)
  365.         PutPMClip();
  366.     return 1;
  367. }
  368.  
  369. int EBuffer::BlockIndent() {
  370.     EPoint B, E;
  371.     int L;
  372.     
  373.     AutoExtend = 0;
  374.     if (CheckBlock() == 0) return 0;
  375.     if (RCount <= 0) return 0;
  376.     B = BB;
  377.     E = BE;
  378.     Draw(B.Row, E.Row);
  379.     if (SetPosR(B.Col, B.Row) == 0) return 0;
  380.     for (L = B.Row; L <= E.Row; L++) {
  381.         switch (BlockMode) {
  382.         case bmStream:
  383.         case bmLine:
  384.             if (L < E.Row || E.Col != 0) {
  385.                 int I = LineIndented(L) + 1;
  386.                 IndentLine(L, I);
  387.             }
  388.             break;
  389.         case bmColumn:
  390.             if (L < E.Row) {
  391.                 if (InsText(L, B.Col, 1, 0) == 0) return 0;
  392.                 if (DelText(L, E.Col, 1) == 0) return 0;
  393.             }
  394.             break;
  395.         }
  396.     }
  397.     if (SetPosR(B.Col, B.Row) == 0) return 0;
  398.     return 1;
  399. }
  400.  
  401. int EBuffer::BlockUnindent() {
  402.     EPoint B, E;
  403.     int L;
  404.     
  405.     AutoExtend = 0;
  406.     if (CheckBlock() == 0) return 0;
  407.     if (RCount <= 0) return 0;
  408.     B = BB;
  409.     E = BE;
  410.     Draw(B.Row, E.Row);
  411.     if (SetPosR(B.Col, B.Row) == 0) return 0;
  412.     for (L = B.Row; L <= E.Row; L++) {
  413.         switch (BlockMode) {
  414.         case bmStream:
  415.         case bmLine:
  416.             if (L < E.Row || E.Col != 0) {
  417.                 int I = LineIndented(L) - 1;
  418.                 if (I >= 0) 
  419.                     IndentLine(L, I);
  420.             }
  421.             break;
  422.         case bmColumn:
  423.             if (L < E.Row) {
  424.                 if (InsText(L, E.Col, 1, 0) == 0) return 0;
  425.                 if (DelText(L, B.Col, 1) == 0) return 0;
  426.             }
  427.             break;
  428.         }
  429.     }
  430.     if (SetPosR(B.Col, B.Row) == 0) return 0;
  431.     return 1;
  432. }
  433.  
  434. int EBuffer::BlockClear() {
  435.     return 0;
  436. }
  437.  
  438. int EBuffer::BlockMarkStream() {
  439.     if (BlockMode != bmStream) BlockUnmark();
  440.     BlockMode= bmStream;
  441.     if (AutoExtend) AutoExtend = 0;
  442.     else {
  443.         BlockUnmark();
  444.         AutoExtend = 1;
  445.     }
  446.     return 1;
  447. }
  448.  
  449. int EBuffer::BlockMarkLine() {
  450.     if (BlockMode != bmLine) BlockUnmark();
  451.     BlockMode= bmLine;
  452.     if (AutoExtend) AutoExtend = 0;
  453.     else {
  454.         BlockUnmark();
  455.         AutoExtend = 1;
  456.     }
  457.     return 1;
  458. }
  459.  
  460. int EBuffer::BlockMarkColumn() {
  461.     if (BlockMode != bmColumn) BlockUnmark();
  462.     BlockMode= bmColumn;
  463.     if (AutoExtend) AutoExtend = 0;
  464.     else {
  465.         BlockUnmark();
  466.         AutoExtend = 1;
  467.     }
  468.     return 1;
  469. }
  470.  
  471. int EBuffer::BlockExtendBegin() {
  472.     CheckBlock();
  473.     ExtendGrab = 0;
  474.     AutoExtend = 0;
  475.     int Y = VToR(CP.Row);
  476.     
  477.     switch (BlockMode) {
  478.     case bmStream:
  479.         if ((Y == BB.Row) && (CP.Col == BB.Col)) ExtendGrab |= 1;
  480.         if ((Y == BE.Row) && (CP.Col == BE.Col)) ExtendGrab |= 2;
  481.         break;
  482.     case bmLine:
  483.         if (Y == BB.Row) ExtendGrab |= 1;
  484.         if (Y == BE.Row) ExtendGrab |= 2;
  485.         break;
  486.     case bmColumn:
  487.         if (Y == BB.Row) ExtendGrab |= 1;
  488.         if (Y == BE.Row) ExtendGrab |= 2;
  489.         if (CP.Col == BB.Col) ExtendGrab |= 4;
  490.         if (CP.Col == BE.Col) ExtendGrab |= 8;
  491.         break;
  492.     }
  493.     
  494.     if (ExtendGrab == 0) {
  495.         BlockBegin();
  496.         BlockEnd();
  497.         if (BlockMode == bmColumn)
  498.             ExtendGrab = 1 | 2 | 4 | 8;
  499.         else 
  500.             ExtendGrab = 1 | 2;
  501.     }    
  502.     return 1;
  503. }
  504.  
  505. int EBuffer::BlockExtendEnd() {
  506.     EPoint T, B, E;
  507.     
  508.     CheckBlock();
  509.     B = BB;
  510.     E = BE;
  511.     switch (BlockMode) {
  512.     case bmLine:
  513.         if (ExtendGrab & 1) { B.Row = VToR(CP.Row); B.Col = 0; }
  514.         else if (ExtendGrab & 2) { E.Row = VToR(CP.Row); E.Col = 0; }
  515.         if (B.Row > E.Row) {
  516.            T = B;
  517.            B = E;
  518.            E = T;
  519.         }
  520.         break;
  521.     case bmStream:
  522.         if (ExtendGrab & 1) { B.Col = CP.Col; B.Row = VToR(CP.Row); }
  523.         else if (ExtendGrab & 2) { E.Col = CP.Col; E.Row = VToR(CP.Row); }
  524.         if ((B.Row > E.Row) ||
  525.             ((B.Row == E.Row) && (B.Col > E.Col))) {
  526.            T = B;
  527.            B = E;
  528.            E = T;
  529.         }
  530.         break;
  531.     case bmColumn:
  532.         if (ExtendGrab & 1) B.Row = VToR(CP.Row);
  533.         else if (ExtendGrab & 2) E.Row = VToR(CP.Row);
  534.         if (ExtendGrab & 4) B.Col = CP.Col;
  535.         else if (ExtendGrab & 8) E.Col = CP.Col;
  536.         if (B.Row > E.Row) {
  537.             int T;
  538.             
  539.             T = B.Row;
  540.             B.Row = E.Row;
  541.             E.Row = T;
  542.         }
  543.         if (B.Col > E.Col) {
  544.             int T;
  545.             
  546.             T = B.Col;
  547.             B.Col = E.Col;
  548.             E.Col = T;
  549.         }
  550.         break;
  551.     }
  552.     SetBB(B);
  553.     SetBE(E);
  554.     ExtendGrab = 0;
  555.     AutoExtend = 0;
  556.     return 1;
  557. }
  558.  
  559. int EBuffer::BlockIsMarked() {
  560.     if ((BB.Row != -1) && (BE.Row != -1) && (BB.Col != -1) && (BE.Col != -1)) return 1;
  561.     return 0;
  562. }
  563.  
  564. int EBuffer::BlockReIndent() {
  565.     EPoint P = CP;
  566.     EPoint B, E;
  567.     
  568.     AutoExtend = 0;
  569.     if (CheckBlock() == 0) return 0;
  570.     if (RCount <= 0) return 0;
  571.     B = BB;
  572.     E = BE;
  573.     Draw(B.Row, E.Row);
  574.     for (int i = B.Row; i < E.Row; i++) {
  575.         if (SetPosR(0, i) == 0) return 0;
  576.         if (LineIndent() == 0) return 0;
  577.     }
  578.     return SetPos(P.Col, P.Row);
  579. }
  580.  
  581. int EBuffer::BlockSelectWord() {
  582.     int Y = VToR(CP.Row);
  583.     PELine L = RLine(Y);
  584.     int P;
  585.     int C;
  586.     
  587.     if (BlockUnmark() == 0) return 0;
  588.     BlockMode = bmStream;
  589.     
  590.     P = CharOffset(L, CP.Col);
  591.     
  592.     if (P >= L->Count) return 0;
  593.     C = ChClassK(L->Chars[P]);
  594.     
  595.     while ((P > 0) && (C == ChClassK(L->Chars[P - 1]))) P--;
  596.     if (SetBB(EPoint(Y, ScreenPos(L, P))) == 0) return 0;
  597.     while ((P < L->Count) && (C == ChClassK(L->Chars[P]))) P++;
  598.     if (SetBE(EPoint(Y, ScreenPos(L, P))) == 0) return 0;
  599.     return 1;
  600. }
  601.  
  602. int EBuffer::BlockSelectLine() {
  603.     int Y = VToR(CP.Row);
  604.     if (BlockUnmark() == 0) return 0;
  605.     BlockMode = bmStream;
  606.     
  607.     if (SetBB(EPoint(Y, 0)) == 0) return 0;
  608.     if (Y == RCount - 1) {
  609.         if (SetBE(EPoint(Y, LineLen(Y))) == 0) return 0;
  610.     } else {
  611.         if (SetBE(EPoint(Y + 1, 0)) == 0) return 0;
  612.     }
  613.     return 1;
  614. }
  615.  
  616. int EBuffer::BlockSelectPara() {
  617.     return 1;
  618. }
  619.  
  620. int EBuffer::BlockWriteTo(char *AFileName, int Append) {
  621.     EPoint B, E;
  622.     int L;
  623.     PELine LL;
  624.     int A, Z;
  625.     FILE *fp;
  626.     int bc = 0, lc = 0, oldc = 0;
  627.     
  628.     AutoExtend = 0;
  629.     if (CheckBlock() == 0) return 0;
  630.     if (RCount == 0) return 0;
  631.     B = BB;
  632.     E = BE;
  633.     Msg(INFO, "Writing %s...", AFileName);
  634.     fp = fopen(AFileName, Append ? "ab" : "wb");
  635.     if (fp == NULL) goto erroropen;
  636.     setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer));
  637.     for (L = B.Row; L <= E.Row; L++) {
  638.         A = -1;
  639.         Z = -1;
  640.         LL = RLine(L);
  641.         switch (BlockMode) {
  642.           case bmLine:
  643.             if (L < E.Row) {
  644.                 A = 0;
  645.                 Z = LL->Count;
  646.             }
  647.             break;
  648.           case bmColumn:
  649.             if (L < E.Row) {
  650.                 A = CharOffset(LL, B.Col);
  651.                 Z = CharOffset(LL, E.Col);
  652.             }
  653.             break;
  654.           case bmStream:
  655.             if (B.Row == E.Row) {
  656.                 A = CharOffset(LL, B.Col);
  657.                 Z = CharOffset(LL, E.Col);
  658.             } else if (L == B.Row) {
  659.                 A = CharOffset(LL, B.Col);
  660.                 Z = LL->Count;
  661.             } else if (L < E.Row) {
  662.                 A = 0;
  663.                 Z  = LL->Count;
  664.             } else if (L == E.Row) {
  665.                 A = 0;
  666.                 Z = CharOffset(LL, E.Col);
  667.             }
  668.             break;
  669.         }
  670.         if (A != -1 && Z != -1) {
  671.             if (A < LL->Count) {
  672.                 if (Z > LL->Count)
  673.                     Z = LL->Count;
  674.                 if (Z > A) {
  675.                     if (fwrite(LL->Chars + A, 1, Z - A, fp) != Z - A) {
  676.                         goto error;
  677.                     } else
  678.                         bc += Z - A;
  679.                 }
  680.             }
  681.             if (BFI(this, BFI_AddCR) == 1)
  682.                 if (fputc(13, fp) < 0) goto error;
  683.                 else
  684.                     bc++;
  685.             if (BFI(this, BFI_AddLF) == 1)
  686.                 if (fputc(10, fp) < 0)
  687.                     goto error;
  688.                 else {
  689.                     bc++;
  690.                     lc++;
  691.                 }
  692.             if (bc > 65536 + oldc) {
  693.                 Msg(INFO, "Writing %s, %d lines, %d bytes.", AFileName, lc, bc);
  694.                 oldc = bc;
  695.             }
  696.         }
  697.     }
  698.     fclose(fp);
  699.     Msg(INFO, "Wrote %s, %d lines, %d bytes.", AFileName, lc, bc);
  700.     return 1;
  701. error:
  702.     fclose(fp);
  703.     unlink(AFileName);
  704. erroropen:
  705.     View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Failed to write block to %s", AFileName);
  706.     return 0;
  707. }
  708.  
  709. int EBuffer::BlockReadFrom(char *AFileName, int blockMode) {
  710.     EBuffer *B;
  711.     int savesys;
  712.     int rc;
  713.  
  714.     if (FileExists(AFileName) == 0) {
  715.         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "File not found: %s", AFileName);
  716.         return 0;
  717.     }
  718.     
  719.     B = new EBuffer(0, (EModel **)&SS, AFileName);
  720.     if (B == 0) return 0;
  721.     B->SetFileName(AFileName, 0);
  722.     if (B->Load() == 0) {
  723.         delete B;
  724.         return 0;
  725.     }
  726.  
  727.     savesys = SystemClipboard;
  728.     SystemClipboard = 0;
  729.  
  730.     switch (blockMode) {
  731.     case bmColumn: rc = BlockPasteColumn(); break;
  732.     case bmLine:   rc = BlockPasteLine(); break;
  733.     default:
  734.     case bmStream: rc = BlockPasteStream(); break;
  735.     }
  736.         
  737.     SystemClipboard = savesys;
  738.  
  739.     if (rc == 0)
  740.         return 0;
  741.     delete B;
  742.     return 1;
  743. }
  744.  
  745. static EBuffer *SortBuffer;
  746. static int SortReverse;
  747. static int *SortRows = 0;
  748. static int SortMinRow;
  749. static int SortMaxRow;
  750. static int SortMinCol;
  751. static int SortMaxCol;
  752.  
  753. static int _LNK_CONV SortProc(const void *A, const void *B) {
  754.     int *AA = (int *)A;
  755.     int *BB = (int *)B;
  756.     ELine *LA = SortBuffer->RLine(*AA);
  757.     ELine *LB = SortBuffer->RLine(*BB);
  758.     int rc;
  759.  
  760.     if (SortMinCol == -1) {
  761.         int lA = LA->Count;
  762.         int lB = LB->Count;
  763.  
  764.         if (BFI(SortBuffer, BFI_MatchCase) == 1)
  765.             rc = memcmp(LA->Chars, LB->Chars, (lA < lB) ? lA : lB);
  766.         else
  767.             rc = memicmp(LA->Chars, LB->Chars, (lA < lB) ? lA : lB);
  768.         if (rc == 0) {
  769.             if (lA > lB)
  770.                 rc = 1;
  771.             else
  772.                 rc = -1;
  773.         }
  774.     } else {
  775.         int lA = LA->Count;
  776.         int lB = LB->Count;
  777.         int PA = SortBuffer->CharOffset(LA, SortMinCol);
  778.         int PB = SortBuffer->CharOffset(LB, SortMinCol);
  779.  
  780.         lA -= PA;
  781.         lB -= PB;
  782.         if (lA < 0 && lB < 0)
  783.             rc = 0;
  784.         else if (lA < 0 && lB > 0)
  785.             rc = -1;
  786.         else if (lA > 0 && lB < 0)
  787.             rc = 1;
  788.         else {
  789.             if (SortMaxCol != -1) {
  790.                 if (lA > SortMaxCol - SortMinCol)
  791.                     lA = SortMaxCol - SortMinCol;
  792.                 if (lB > SortMaxCol - SortMinCol)
  793.                     lB = SortMaxCol - SortMinCol;
  794.             }
  795.             if (BFI(SortBuffer, BFI_MatchCase) == 1)
  796.                 rc = memcmp(LA->Chars+ PA, LB->Chars + PB, (lA < lB) ? lA : lB);
  797.             else
  798.                 rc = memicmp(LA->Chars + PA, LB->Chars + PB, (lA < lB) ? lA : lB);
  799.             if (rc == 0) {
  800.                 if (lA > lB)
  801.                     rc = 1;
  802.                 else
  803.                     rc = -1;
  804.             }
  805.         }
  806.     }
  807.  
  808.     if (SortReverse)
  809.         return -rc;
  810.     return rc;
  811. }
  812.  
  813. int EBuffer::BlockSort(int Reverse) {
  814.     int rq;
  815.     ELine *oldL;
  816.     
  817.     if (CheckBlock() == 0) return 0;
  818.     if (RCount == 0) return 0;
  819.  
  820.     SortMinRow = BB.Row;
  821.     SortMaxRow = BE.Row;
  822.     if (BlockMode != bmStream || BE.Col == 0)
  823.         SortMaxRow--;
  824.  
  825.     if (SortMinRow >= SortMaxRow)
  826.         return 1;
  827.  
  828.     SortBuffer = this;
  829.     SortReverse = Reverse;
  830.     switch (BlockMode) {
  831.     case bmLine:
  832.     case bmStream:
  833.         SortMinCol = -1;
  834.         SortMaxCol = -1;
  835.         break;
  836.  
  837.     case bmColumn:
  838.         SortMinCol = BB.Col;
  839.         SortMaxCol = BE.Col;
  840.         break;
  841.     }
  842.  
  843.     SortRows = (int *)malloc((SortMaxRow - SortMinRow + 1) * sizeof(int));
  844.     if (SortRows == 0) {
  845.         free(SortRows);
  846.         return 0;
  847.     }
  848.     for (rq = 0; rq <= SortMaxRow - SortMinRow; rq++)
  849.         SortRows[rq] = rq + SortMinRow;
  850.  
  851.     qsort(SortRows, SortMaxRow - SortMinRow + 1, sizeof(int), SortProc);
  852.  
  853.     // now change the order of lines according to new order in Rows array.
  854.  
  855.     for (rq = 0; rq <= SortMaxRow - SortMinRow; rq++) {
  856.         oldL = RLine(SortRows[rq]);
  857.         if (InsLine(1 + rq + SortMaxRow, 0) == 0)
  858.             return 0;
  859.         if (InsChars(1 + rq + SortMaxRow, 0, oldL->Count, oldL->Chars) == 0)
  860.             return 0;
  861.     }
  862.  
  863.     for (rq = 0; rq <= SortMaxRow - SortMinRow; rq++)
  864.         if (DelLine(SortMinRow) == 0)
  865.             return 0;
  866.     
  867.     free(SortRows);
  868.     return 1;
  869. }
  870.  
  871. int EBuffer::BlockUnTab() {
  872.     EPoint B, E;
  873.     ELine *L;
  874.     int O, C;
  875.     
  876.     AutoExtend = 0;
  877.     if (CheckBlock() == 0) return 0;
  878.     if (RCount <= 0) return 0;
  879.     B = BB;
  880.     E = BE;
  881.     Draw(B.Row, E.Row);
  882.     for (int i = B.Row; i < E.Row; i++) {
  883.         L = RLine(i);
  884.         O = 0;
  885.         C = 0;
  886.         while (O < L->Count) {
  887.             if (L->Chars[O] == '\t') {
  888.                 C = NextTab(C, BFI(this, BFI_TabSize));
  889.                 
  890.                 if (DelChars(i, O, 1) != 1)
  891.                     return 0;
  892.                 if (InsChars(i, O, C - O, 0) != 1)
  893.                     return 0;
  894.                 O = C;
  895.             } else {
  896.                 O++;
  897.                 C++;
  898.             }
  899.         }
  900.     }
  901.     return 1;
  902. }
  903.  
  904. int EBuffer::BlockEnTab() {
  905.     EPoint B, E;
  906.     ELine *L;
  907.     int O, C, O1, C1;
  908.     char tab = '\t';
  909.     
  910.     AutoExtend = 0;
  911.     if (CheckBlock() == 0) return 0;
  912.     if (RCount <= 0) return 0;
  913.     B = BB;
  914.     E = BE;
  915.     Draw(B.Row, E.Row);
  916.     for (int i = B.Row; i < E.Row; i++) {
  917.         L = RLine(i);
  918.         O = C = 0;
  919.         O1 = C1 = 0;
  920.         while (O < L->Count) {
  921.             if (L->Chars[O] == '\t') { // see if there are spaces to remove
  922.                 int C2 = NextTab(C, BFI(this, BFI_TabSize));
  923.                 int N = BFI(this, BFI_TabSize) - (C2 - C);
  924.                 if (O - O1 < N)
  925.                     N = O - O1;
  926.                 if (N > 0) {
  927.                     if (DelChars(i, O - N, N) != 1)
  928.                         return 0;
  929.                     O -= N;
  930.                     C = C2;
  931.                     O++;
  932.                     C1 = C;
  933.                     O1 = O;
  934.                 } else {
  935.                     O++;
  936.                     C = C2;
  937.                     O1 = O;
  938.                     C1 = C;
  939.                 }
  940.             } else if (L->Chars[O] != ' ') { // nope, cannot put tab here
  941.                 O++;
  942.                 C++;
  943.                 C1 = C;
  944.                 O1 = O;
  945.             } else if (((C % BFI(this, BFI_TabSize)) == (BFI(this, BFI_TabSize) - 1)) &&
  946.                        (C - C1 > 0))
  947.             { // reached a tab and can put one
  948.                 int N = BFI(this, BFI_TabSize);
  949.                 if (O - O1 + 1 < N) {
  950.                     N = O - O1 + 1;
  951.                 } else if (O - O1 + 1 > N) {
  952.                     O1 = O - N + 1;
  953.                 }
  954.                 if (DelChars(i, O1, N) != 1)
  955.                     return 0;
  956.                 if (InsChars(i, O1, 1, &tab) != 1)
  957.                     return 0;
  958.                 O1++;
  959.                 O = O1;
  960.                 C++;
  961.                 C1 = C;
  962.             } else {
  963.                 O++;
  964.                 C++;
  965.             }
  966.         }
  967.     }
  968.     return 1;
  969. }
  970.  
  971. // FindFunction -- search for line matching 'RoutineRegexp'
  972. // starting from current line + 'delta'. 'way' should be +1 or -1.
  973. int EBuffer::FindFunction(int delta, int way) {
  974.     RxNode     *regx;
  975.     int         line;
  976.     PELine      L;
  977.     RxMatchRes  res;
  978.  
  979.     if (BFS(this, BFS_RoutineRegexp) == 0) {
  980.         View->MView->Win->Choice(GPC_ERROR, "Error", 1,
  981.                                  "O&K", "No routine regexp.");
  982.         return -1;
  983.     }
  984.     regx = RxCompile(BFS(this, BFS_RoutineRegexp));
  985.     if (regx == 0) {
  986.         View->MView->Win->Choice(GPC_ERROR, "Error", 1,
  987.                                  "O&K", "Failed to compile regexp '%s'",
  988.                                  BFS(this, BFS_RoutineRegexp));
  989.         return -1;
  990.     }
  991.  
  992.     //** Scan backwards from the current cursor position,
  993.     Msg(BUSY, "Matching %s", BFS(this, BFS_RoutineRegexp));
  994.     line = VToR(CP.Row) + delta;
  995.     while (line >= 0 && line < RCount) {
  996.         L = RLine(line);
  997.         if (RxExec(regx, L->Chars, L->Count, L->Chars, &res) == 1)
  998.             break;
  999.         line += way;
  1000.     }
  1001.     if (line < 0)
  1002.         line = 0;
  1003.     if (line >= RCount)
  1004.         line = RCount - 1;
  1005.     RxFree(regx);
  1006.     return line;
  1007. }
  1008.  
  1009. // Selects the current function.
  1010. int EBuffer::BlockMarkFunction() {
  1011.     int by, ey;
  1012.  
  1013.     if (BlockUnmark() == 0)
  1014.         return 0;
  1015.  
  1016.     if ((by = FindFunction( 0, -1)) == -1)
  1017.         return 0;
  1018.     if ((ey = FindFunction(+1, +1)) == -1)
  1019.         return 0;
  1020.  
  1021.     //** Start and end are known. Set the block;
  1022.     BlockMode = bmStream;
  1023.     if (SetBB(EPoint(by, 0)) == 0)
  1024.         return 0;
  1025.     if (SetBE(EPoint(ey, 0)) == 0)
  1026.         return 0;
  1027.  
  1028.     return 1;
  1029. }
  1030.  
  1031. int EBuffer::IndentFunction() {
  1032.     EPoint P = CP;
  1033.     int by, ey;
  1034.  
  1035.     if ((by = FindFunction( 0, -1)) == -1)
  1036.         return 0;
  1037.     if ((ey = FindFunction(+1, +1)) == -1)
  1038.         return 0;
  1039.  
  1040.     //Draw(by, ey); ?
  1041.     for (int i = by; i < ey; i++) {
  1042.         if (SetPosR(0, i) == 0)
  1043.             return 0;
  1044.         if (LineIndent() == 0)
  1045.             return 0;
  1046.     }
  1047.     return SetPos(P.Col, P.Row);
  1048. }
  1049.  
  1050. int EBuffer::MoveFunctionPrev() {
  1051.     int line = FindFunction(-1, -1);
  1052.  
  1053.     if (line == -1)
  1054.         return 0;
  1055.  
  1056.     return CenterPosR(0, line);
  1057. }
  1058.  
  1059. int EBuffer::MoveFunctionNext() {
  1060.     int line = FindFunction(+1, +1);
  1061.  
  1062.     if (line == -1)
  1063.         return 0;
  1064.  
  1065.     return CenterPosR(0, line);
  1066. }
  1067.