1 /*    e_buffer.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 "e_buffer.h"
11 
12 #include "c_bind.h"
13 #include "c_config.h"
14 #include "c_history.h"
15 #include "e_mark.h"
16 #include "e_undo.h"
17 #include "i_modelview.h"
18 #include "i_view.h"
19 #include "o_routine.h"
20 #include "s_util.h"
21 
22 EBuffer *SSBuffer = 0; // scrap buffer (clipboard)
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 
EBuffer(int createFlags,EModel ** ARoot,const char *)26 EBuffer::EBuffer(int createFlags, EModel **ARoot, const char * /*AName*/) :
27     EModel(createFlags, ARoot),
28     FileName(0),
29     Modified(0),
30     TP(0,0),
31     CP(0,0),
32     BB(-1,-1),
33     BE(-1,-1),
34     PrevPos(-1, -1),
35     SavedPos(-1, -1),
36     BlockMode(bmStream),
37     ExtendGrab(0),
38     AutoExtend(0),
39     Loaded(0),
40     Loading(0),
41     RAllocated(0),
42     RGap(0),
43     RCount(0),
44     LL(0),
45     VAllocated(0),
46     VGap(0),
47     VCount(0),
48     VV(0),
49 #ifdef CONFIG_FOLDS
50     FCount(0),
51     FF(0),
52 #endif
53     Match(-1, -1),
54     MatchLen(0),
55     MatchCount(0),
56     MinRedraw(-1),
57     MaxRedraw(-1),
58     RedrawToEos(0)
59 {
60 #ifdef CONFIG_UNDOREDO
61     US.Num = 0;
62     US.Data = 0;
63     US.Top = 0;
64     US.UndoPtr = 0;
65     US.NextCmd = 1;
66     US.Record = 1;
67     US.Undo = 0;
68 #endif
69 #ifdef CONFIG_OBJ_ROUTINE
70     rlst.Count = 0;
71     rlst.Lines = 0;
72     Routines = 0;
73 #endif
74     //Name = strdup(AName);
75     Allocate(0);
76     AllocVis(0);
77     Mode = GetModeForName("");
78     Flags = (Mode->Flags);
79     BFI(this, BFI_Undo) = 0;
80     BFI(this, BFI_ReadOnly) = 0;
81 #ifdef CONFIG_SYNTAX_HILIT
82     StartHilit = 0;
83     EndHilit = -1;
84     HilitProc = 0;
85     if (Mode && Mode->fColorize)
86         HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser);
87 #endif
88     InsertLine(CP,0,0); /* there should always be at least one line in the edit buffer */
89     Flags = (Mode->Flags);
90     Modified = 0;
91 }
92 
~EBuffer()93 EBuffer::~EBuffer() {
94 #ifdef CONFIG_HISTORY
95     if (FileName != 0 && Loaded) {
96         UpdateFPos(FileName, VToR(CP.Row), CP.Col);
97 #ifdef CONFIG_BOOKMARKS
98         if (BFI (this,BFI_SaveBookmarks)==3) StoreBookmarks(this);
99 #endif
100     }
101 #endif
102     if (FileName && Loaded)
103         markIndex.storeForBuffer(this);
104 
105     Clear();
106     if (LL)
107 	free(LL);
108     //free(Name);
109     if (FileName)
110 	free(FileName);
111 #ifdef CONFIG_BOOKMARKS
112     vector_iterate(EBookmark*, BMarks, it)
113 	delete *it;
114 #endif
115 #ifdef CONFIG_OBJ_ROUTINE
116     if (rlst.Lines) {
117         free(rlst.Lines);
118         rlst.Lines = 0;
119     }
120     DeleteRelated();
121 #endif
122 }
123 
DeleteRelated()124 void EBuffer::DeleteRelated() {
125 #ifdef CONFIG_OBJ_ROUTINE
126     if (Routines) {
127         ::ActiveView->DeleteModel(Routines);
128         Routines = 0;
129     }
130 #endif
131 }
132 
Clear()133 int EBuffer::Clear() {
134     Modified = 1;
135 #ifdef CONFIG_SYNTAX_HILIT
136     EndHilit = -1;
137     StartHilit = 0;
138     WordList.clear();
139 #endif
140 #ifdef CONFIG_OBJ_ROUTINE
141     rlst.Count = 0;
142     if (rlst.Lines) {
143         free(rlst.Lines);
144         rlst.Lines = 0;
145     }
146 #endif
147     if (LL)
148     {
149 	for (int i = 0; i < RCount; i++)
150 	    delete LL[GapLine(i, RGap, RCount, RAllocated)];
151 	free(LL);
152 	LL = 0;
153     }
154     RCount = RAllocated = RGap = 0;
155     VCount = VAllocated = VGap = 0;
156     if (VV)
157     {
158         free(VV);
159 	VV = 0;
160     }
161 #ifdef CONFIG_UNDOREDO
162     FreeUndo();
163 #endif
164 
165 #ifdef CONFIG_FOLDS
166     if (FCount != 0) {
167         free(FF);
168         FCount = 0;
169         FF = 0;
170     }
171 #endif
172 
173     return 0;
174 }
175 
176 #ifdef CONFIG_UNDOREDO
FreeUndo()177 int EBuffer::FreeUndo() {
178     for (int j = 0; j < US.Num; j++)
179         free(US.Data[j]);
180     free(US.Top);
181     free(US.Data);
182     US.Num = 0;
183     US.Data = 0;
184     US.Top = 0;
185     US.Undo = 0;
186     US.Record = 1;
187     US.UndoPtr = 0;
188     return 1;
189 }
190 #endif
191 
Modify()192 int EBuffer::Modify() {
193     // if RecheckReadOnly is activated do readonly checking when necessary
194     if (RecheckReadOnly != 0)
195     {
196         if (BFI(this, BFI_ReadOnly)) {
197             // File might have been toggled writable outside the editor, or
198             //  you might do what I do, and do a Tools/Run/"p4 edit Filename.cpp"
199             //  from inside FTE, and it's a pain to manually reopen the file, so
200             //  recheck writability here instead. Note that we don't check the
201             //  converse, since in reality this is rarely a problem, and the
202             //  file save routines will check this (oh well).  --ryan.
203             struct stat StatBuf;
204             if ((FileName != 0) && FileOk && (stat(FileName, &StatBuf) == 0)) {
205                 if (!(StatBuf.st_mode & (S_IWRITE | S_IWGRP | S_IWOTH)))
206                     BFI(this, BFI_ReadOnly) = 1;
207                 else
208                     BFI(this, BFI_ReadOnly) = 0;
209             }
210         }
211     }
212 
213     if (BFI(this, BFI_ReadOnly)) {
214         Msg(S_ERROR, "File is read-only.");
215         return 0;
216     }
217     if (Modified == 0) {
218         struct stat StatBuf;
219 
220         if ((FileName != 0) && FileOk && (stat(FileName, &StatBuf) == 0)) {
221             if (FileStatus.st_size != StatBuf.st_size ||
222                 FileStatus.st_mtime != StatBuf.st_mtime)
223             {
224                 View->MView->Win->Choice(GPC_ERROR, "Warning! Press Esc!",
225                                          0,
226                                          "File %-.55s changed on disk!",
227                                          FileName);
228                 switch (View->MView->Win->Choice(0, "File Changed on Disk",
229                                2,
230                                "&Modify",
231                                "&Cancel",
232                                "%s", FileName))
233                 {
234                 case 0:
235                     break;
236                 case 1:
237                 case -1:
238                 default:
239                     return 0;
240                 }
241             }
242         }
243 #ifdef CONFIG_UNDOREDO
244         if (BFI(this, BFI_Undo))
245             if (PushUChar(ucModified) == 0) return 0;
246 #endif
247     }
248     Modified++;
249     if (Modified == 0) Modified++;
250     return 1;
251 }
252 
LoadRegion(EPoint *,int,int,int)253 int EBuffer::LoadRegion(EPoint * /*A*/, int /*FH*/, int /*StripChar*/, int /*LineChar*/) {
254     return 0;
255 }
256 
257 /*
258 int EBuffer::AddLine(const char *AChars) {
259     if (InsLine(Pos.Row, 0) == 0) return 0;
260     if (InsText(Pos.Row, Pos.Col, ACount, AChars) == 0) return 0;
261     return 1;
262 }
263 */
264 
InsertLine(const EPoint & Pos,size_t ACount,const char * AChars)265 int EBuffer::InsertLine(const EPoint& Pos, size_t ACount, const char *AChars) {
266     if (!InsLine(Pos.Row, 0))
267         return 0;
268     return InsText(Pos.Row, Pos.Col, ACount, AChars);
269 }
270 
UpdateMark(EPoint & M,int Type,int Row,int Col,int Rows,int Cols)271 int EBuffer::UpdateMark(EPoint &M, int Type, int Row, int Col, int Rows, int Cols) {
272     switch (Type) {
273     case umInsert: /* text inserted */
274         switch (BlockMode) {
275         case bmLine:
276         case bmColumn:
277             if (M.Row >= Row)
278                 M.Row += Rows;
279             break;
280         case bmStream:
281             if (Cols) {
282                 if (M.Row == Row)
283                     if (M.Col >= Col)
284                         M.Col += Cols;
285             }
286             if (Rows) {
287                 if (M.Row >= Row)
288                     M.Row += Rows;
289             }
290             break;
291         }
292         break;
293     case umDelete:
294         switch (BlockMode) {
295         case bmLine:
296         case bmColumn:
297             if (M.Row >= Row) {
298                 if (InRange(Row, M.Row, Row + Rows))
299                     M.Row = Row;
300                 else
301                     M.Row -= Rows;
302             }
303             break;
304         case bmStream:
305             if (Cols) {
306                 if (M.Row == Row)
307                     if (M.Col >= Col) {
308                         if (M.Col < Col + Cols)
309                             M.Col = Col;
310                         else
311                             M.Col -= Cols;
312                     }
313             }
314             if (Rows) {
315                 if (M.Row >= Row) {
316                     if (M.Row < Row + Rows) {
317                         M.Row = Row;
318                         M.Col = 0;
319                     } else M.Row -= Rows;
320                 }
321             }
322         }
323         break;
324     case umSplitLine:
325         switch (BlockMode) {
326         case bmLine:
327         case bmColumn:
328             if (M.Row == Row) {
329                 if (Col <= M.Col) {
330                     M.Row++;
331                     M.Col -= Col;
332                 }
333             } else if (M.Row > Row) M.Row++;
334             break;
335         case bmStream:
336             if (M.Row == Row) {
337                 if (Col <= M.Col) {
338                     M.Row++;
339                     M.Col -= Col;
340                 }
341             } else if (M.Row > Row) M.Row++;
342             break;
343         }
344         break;
345     case umJoinLine:
346         switch (BlockMode) {
347         case bmLine:
348         case bmColumn:
349             if (M.Row == Row + 1)
350                 M.Row--;
351             else if (M.Row > Row) M.Row--;
352             break;
353         case bmStream:
354             if (M.Row == Row + 1) {
355                 M.Row--;
356                 M.Col += Col;
357             } else if (M.Row > Row) M.Row--;
358             break;
359         }
360         break;
361     }
362     return 1;
363 }
364 
UpdateMarker(int Type,int Row,int Col,int Rows,int Cols)365 int EBuffer::UpdateMarker(int Type, int Row, int Col, int Rows, int Cols) {
366     EPoint OldBB = BB, OldBE = BE;
367     EView *V;
368 
369     UpdateMark(SavedPos, Type, Row, Col, Rows, Cols);
370     UpdateMark(PrevPos, Type, Row, Col, Rows, Cols);
371 
372     UpdateMark(BB, Type, Row, Col, Rows, Cols);
373     UpdateMark(BE, Type, Row, Col, Rows, Cols);
374 
375     V = View;
376     while (V) {
377         if (V->Model != this)
378             assert(1 == 0);
379         if (V != View) {
380             EPoint M;
381 
382             M = GetViewVPort(V)->TP;
383             UpdateMark(GetViewVPort(V)->TP, Type, Row, Col, Rows, Cols);
384             GetViewVPort(V)->TP.Col = M.Col;
385             UpdateMark(GetViewVPort(V)->CP, Type, Row, Col, Rows, Cols);
386         }
387         V = V->NextView;
388     }
389 
390 #ifdef CONFIG_OBJ_ROUTINE
391     for (int i = 0; i < rlst.Count && rlst.Lines; i++) {
392         EPoint M;
393 
394         M.Col = 0;
395         M.Row = rlst.Lines[i];
396         UpdateMark(M, Type, Row, Col, Rows, Cols);
397         rlst.Lines[i] = M.Row;
398     }
399 #endif
400 #ifdef CONFIG_FOLDS
401     for (int f = 0; f < FCount; f++) {
402         EPoint M;
403 
404         M.Col = 0;
405         M.Row = FF[f].line;
406         UpdateMark(M, Type, Row, Col, Rows, Cols);
407         FF[f].line = M.Row;
408     }
409 #endif
410 #ifdef CONFIG_BOOKMARKS
411     vector_iterate(EBookmark*, BMarks, it)
412         UpdateMark((*it)->GetPoint(), Type, Row, Col, Rows, Cols);
413 #endif
414 
415     if (OldBB.Row != BB.Row) {
416         int MinL = Min(OldBB.Row, BB.Row);
417         int MaxL = Max(OldBB.Row, BB.Row);
418         if (MinL != -1 && MaxL != -1)
419             Draw(MinL, MaxL);
420     }
421     if (OldBE.Row != BE.Row) {
422         int MinL = Min(OldBE.Row, BE.Row);
423         int MaxL = Max(OldBE.Row, BE.Row);
424         if (MinL != -1 && MaxL != -1)
425             Draw(MinL, MaxL);
426     }
427     return 1;
428 }
429 
ValidPos(EPoint Pos)430 int EBuffer::ValidPos(EPoint Pos) {
431     if ((Pos.Col >= 0) &&
432         (Pos.Row >= 0) &&
433         (Pos.Row < VCount))
434         return 1;
435     return 0;
436 }
437 
RValidPos(EPoint Pos)438 int EBuffer::RValidPos(EPoint Pos) {
439     if ((Pos.Col >= 0) &&
440         (Pos.Row >= 0) &&
441         (Pos.Row < RCount))
442         return 1;
443     return 0;
444 }
445 
AssertLine(int Row)446 int EBuffer::AssertLine(int Row) {
447     if (Row == RCount)
448         if (!InsLine(RCount, 0))
449             return 0;
450 
451     return 1;
452 }
453 
SetFileName(const char * AFileName,const char * AMode)454 int EBuffer::SetFileName(const char *AFileName, const char *AMode) {
455     FileOk = 0;
456 
457     free(FileName);
458     FileName = strdup(AFileName);
459     Mode = 0;
460     if (AMode) {
461         if (!(Mode = FindMode(AMode))) {
462             StlString AMODE(AMode);
463             AMODE.toupper();
464             Mode = FindMode(AMODE.c_str());
465         }
466     }
467     if (Mode == 0)
468         Mode = GetModeForName(AFileName);
469     assert(Mode != 0);
470     Flags = (Mode->Flags);
471 #ifdef CONFIG_SYNTAX_HILIT
472     HilitProc = 0;
473     if (Mode && Mode->fColorize)
474         HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser);
475 #endif
476     UpdateTitle();
477     return FileName?1:0;
478 }
479 
SetPos(int Col,int Row,int tabMode)480 int EBuffer::SetPos(int Col, int Row, int tabMode) {
481     if (!VCount)
482         return 1;
483     assert (Col >= 0 && Row >= 0 && Row < VCount);
484 
485 #ifdef CONFIG_UNDOREDO
486     if (BFI(this, BFI_Undo) == 1 && BFI(this, BFI_UndoMoves) == 1) {
487         if (PushULong(CP.Col) == 0) return 0;
488         if (PushULong(CP.Row) == 0) return 0;
489         if (PushUChar(ucPosition) == 0) return 0;
490     }
491 #endif
492     if (AutoExtend) {
493         BlockExtendBegin();
494         AutoExtend = 1;
495     }
496     PrevPos = CP;
497     PrevPos.Row = (CP.Row < VCount) ? VToR(CP.Row) : (CP.Row - VCount + RCount);
498     CP.Row = Row;
499     CP.Col = Col;
500     if (AutoExtend) {
501         BlockExtendEnd();
502         AutoExtend = 1;
503     }
504     //        if (View && View->Model == this ) {
505     //            View->GetVPort();
506     //        }
507     if (BFI(this, BFI_CursorThroughTabs) == 0) {
508         if (tabMode == tmLeft) {
509             if (MoveTabStart() == 0) return 0;
510         } else if (tabMode == tmRight) {
511             if (MoveTabEnd() == 0) return 0;
512         }
513     }
514     if (ExtendGrab == 0 && AutoExtend == 0 && BFI(this, BFI_PersistentBlocks) == 0) {
515         if (CheckBlock() == 1)
516             if (BlockUnmark() == 0)
517                 return 0;
518     }
519     return 1;
520 }
521 
SetPosR(int Col,int Row,int tabMode)522 int EBuffer::SetPosR(int Col, int Row, int tabMode) {
523     assert (Row >= 0 && Row < RCount && Col >= 0);
524 
525     int L = RToV(Row);
526 
527     if (L == -1)
528         if (ExposeRow(Row) == 0) return 0;
529 
530     L = RToV(Row);
531 
532     return SetPos(Col, L, tabMode);
533 }
534 
SetNearPos(int Col,int Row,int tabMode)535 int EBuffer::SetNearPos(int Col, int Row, int tabMode) {
536     if (Row >= VCount) Row = VCount - 1;
537     if (Row < 0) Row = 0;
538     if (Col < 0) Col = 0;
539     return SetPos(Col, Row, tabMode);
540 }
541 
SetNearPosR(int Col,int Row,int tabMode)542 int EBuffer::SetNearPosR(int Col, int Row, int tabMode) {
543     if (Row >= RCount) Row = RCount - 1;
544     if (Row < 0) Row = 0;
545     if (Col < 0) Col = 0;
546     return SetPosR(Col, Row, tabMode);
547 }
548 
CenterPos(int Col,int Row,int tabMode)549 int EBuffer::CenterPos(int Col, int Row, int tabMode) {
550     assert(Row >= 0 && Row < VCount && Col >= 0);
551 
552     if (SetPos(Col, Row, tabMode) == 0) return 0;
553     if (View && View->Model == this) {
554         Row -= GetVPort()->Rows / 2;
555         if (Row < 0) Row = 0;
556         Col -= GetVPort()->Cols - 8;
557         if (Col < 0) Col = 0;
558         if (GetVPort()->SetTop(Col, Row) == 0) return 0;
559         GetVPort()->ReCenter = 1;
560     }
561     return 1;
562 }
563 
CenterPosR(int Col,int Row,int tabMode)564 int EBuffer::CenterPosR(int Col, int Row, int tabMode) {
565     int L;
566 
567     assert(Row >= 0 && Row < RCount && Col >= 0);
568 
569     L = RToV(Row);
570     if (L == -1)
571         if (ExposeRow(Row) == 0) return 0;
572     L = RToV(Row);
573     return CenterPos(Col, L, tabMode);
574 }
575 
CenterNearPos(int Col,int Row,int tabMode)576 int EBuffer::CenterNearPos(int Col, int Row, int tabMode) {
577     if (Row >= VCount) Row = VCount - 1;
578     if (Row < 0) Row = 0;
579     if (Col < 0) Col = 0;
580     return CenterPos(Col, Row, tabMode);
581 }
582 
CenterNearPosR(int Col,int Row,int tabMode)583 int EBuffer::CenterNearPosR(int Col, int Row, int tabMode) {
584     if (Row >= RCount) Row = RCount - 1;
585     if (Row < 0) Row = 0;
586     if (Col < 0) Col = 0;
587     return CenterPosR(Col, Row, tabMode);
588 }
589 
LineLen(int Row)590 int EBuffer::LineLen(int Row) {
591     assert(Row >= 0 && Row < RCount);
592     PELine L = RLine(Row);
593     return ScreenPos(L, L->Count);
594 }
595 
LineChars(int Row)596 int EBuffer::LineChars(int Row) {
597     assert(Row >= 0 && Row < RCount);
598     return RLine(Row)->Count;
599 }
600 
DelLine(int Row,int DoMark)601 int EBuffer::DelLine(int Row, int DoMark) {
602     int VLine;
603     int GapSize;
604 //    printf("DelLine: %d\n", Row);
605     if (Row < 0) return 0;
606     if (Row >= RCount) return 0;
607     if (Modify() == 0) return 0;
608 
609     VLine = RToV(Row);
610     if (VLine == -1)
611         if (ExposeRow(Row) == 0) return 0;
612     VLine = RToV(Row);
613     assert(VLine != -1);
614 
615 #ifdef CONFIG_FOLDS
616     if (FindFold(Row) != -1) {
617         if (FoldDestroy(Row) == 0) return 0;
618     }
619 #endif
620 
621     VLine = RToV(Row);
622     assert(VLine != -1);
623 
624 #ifdef CONFIG_UNDOREDO
625     if (BFI(this, BFI_Undo) == 1) {
626         if (PushUData(RLine(Row)->Chars, RLine(Row)->Count) == 0) return 0;
627         if (PushULong(RLine(Row)->Count) == 0) return 0;
628         if (PushULong(Row) == 0) return 0;
629         if (PushUChar(ucDelLine) == 0) return 0;
630     }
631 #endif
632     if (DoMark)
633         UpdateMarker(umDelete, Row, 0, 1, 0);
634     //puts("Here");
635 
636     Draw(Row, -1);
637     Hilit(Row);
638     assert(RAllocated >= RCount);
639     if (RGap != Row)
640         if (MoveRGap(Row) == 0) return 0;
641 
642     GapSize = RAllocated - RCount;
643 
644     delete LL[RGap + GapSize];
645     LL[RGap + GapSize] = 0;
646     RCount--;
647     GapSize++;
648     if (RAllocated - RAllocated / 2 > RCount) {
649         memmove(LL + RGap + GapSize - RAllocated / 3,
650                 LL + RGap + GapSize,
651                 sizeof(PELine) * (RCount - RGap));
652         if (Allocate(RAllocated - RAllocated / 3) == 0) return 0;
653     }
654 
655     assert(VAllocated >= VCount);
656     if (VGap != VLine)
657         if (MoveVGap(VLine) == 0) return 0;
658     GapSize = VAllocated - VCount;
659     VV[VGap + GapSize] = 0;
660     VCount--;
661     GapSize++;
662     if (VAllocated - VAllocated / 2 > VCount) {
663         memmove(VV + VGap + GapSize - VAllocated / 3,
664                 VV + VGap + GapSize,
665                 sizeof(VV[0]) * (VCount - VGap));
666         if (AllocVis(VAllocated - VAllocated / 3) == 0) return 0;
667     }
668     return 1;
669 }
670 
InsLine(int Row,int DoAppend,int DoMark)671 int EBuffer::InsLine(int Row, int DoAppend, int DoMark) {
672     PELine L;
673     int VLine = -1;
674 
675     //    printf("InsLine: %d\n", Row);
676 
677     //if (! LL)
678     //   return 0;
679     if (Row < 0) return 0;
680     if (Row > RCount) return 0;
681     if (Modify() == 0) return 0;
682     if (DoAppend) {
683         Row++;
684     }
685     if (Row < RCount) {
686         VLine = RToV(Row);
687         if (VLine == -1)
688             if (ExposeRow(Row) == 0) return 0;
689         VLine = RToV(Row);
690         assert(VLine != -1);
691     } else {
692         VLine = VCount;
693     }
694     L = new ELine(0, (char *)0);
695     if (L == 0) return 0;
696 #ifdef CONFIG_UNDOREDO
697     if (BFI(this, BFI_Undo) == 1) {
698         if (PushULong(Row) == 0) return 0;
699         if (PushUChar(ucInsLine) == 0) return 0;
700     }
701 #endif
702     if (DoMark)
703         UpdateMarker(umInsert, Row, 0, 1, 0);
704     Draw(Row, -1);
705     Hilit(Row);
706     VLine = RToVN(Row);
707     assert(RCount <= RAllocated);
708 //    printf("++ %d G:C:A :: %d - %d - %d\n", Row, RGap, RCount, RAllocated);
709     if (RCount == RAllocated) {
710         if (Allocate(RCount ? (RCount * 2) : 1) == 0) return 0;
711         memmove(LL + RAllocated - (RCount - RGap),
712                 LL + RGap,
713                 sizeof(PELine) * (RCount - RGap));
714     }
715     if (RGap != Row)
716         if (MoveRGap(Row) == 0) return 0;
717     LL[RGap] = L;
718     RGap++;
719     RCount++;
720     //    printf("-- %d G:C:A :: %d - %d - %d\n", Row, RGap, RCount, RAllocated);
721 
722     assert(VCount <= VAllocated);
723     if (VCount == VAllocated) {
724         if (AllocVis(VCount ? (VCount * 2) : 1) == 0) return 0;
725         memmove(VV + VAllocated - (VCount - VGap),
726                 VV + VGap,
727                 sizeof(VV[0]) * (VCount - VGap));
728     }
729     if (VGap != VLine)
730         if (MoveVGap(VLine) == 0) return 0;
731     VV[VGap] = Row - VGap;
732     VGap++;
733     VCount++;
734 
735 /*    if (AllocVis(VCount + 1) == 0) return 0;
736     memmove(VV + VLine + 1, VV + VLine, sizeof(VV[0]) * (VCount - VLine));
737     VCount++;
738     Vis(VLine, Row - VLine);*/
739     return 1;
740 }
741 
DelChars(int Row,int Ofs,size_t ACount)742 int EBuffer::DelChars(int Row, int Ofs, size_t ACount) {
743     PELine L;
744 
745 //    printf("DelChars: %d:%d %d\n", Row, Ofs, ACount);
746     if (Row < 0) return 0;
747     if (Row >= RCount) return 0;
748     L = RLine(Row);
749 
750     if (Ofs < 0) return 0;
751     if (Ofs >= L->Count) return 0;
752     if (Ofs + ACount >= L->Count)
753         ACount = L->Count - Ofs;
754     if (ACount == 0) return 1;
755 
756     if (Modify() == 0) return 0;
757 
758 #ifdef CONFIG_UNDOREDO
759     if (BFI(this, BFI_Undo) == 1) {
760         if (PushUData(L->Chars + Ofs, ACount) == 0) return 0;
761         if (PushULong(ACount) == 0) return 0;
762         if (PushULong(Ofs) == 0) return 0;
763         if (PushULong(Row) == 0) return 0;
764         if (PushUChar(ucDelChars) == 0) return 0;
765     }
766 #endif
767 
768     if (L->Count > Ofs + ACount)
769         memmove(L->Chars + Ofs, L->Chars + Ofs + ACount, L->Count - Ofs - ACount);
770     L->Count -= ACount;
771     if (L->Allocate(L->Count) == 0) return 0;
772     Draw(Row, Row);
773     Hilit(Row);
774 //    printf("OK\n");
775     return 1;
776 }
777 
InsChars(int Row,int Ofs,size_t ACount,const char * Buffer)778 int EBuffer::InsChars(int Row, int Ofs, size_t ACount, const char *Buffer) {
779     PELine L;
780 
781 //    printf("InsChars: %d:%d %d\n", Row, Ofs, ACount);
782 
783     assert(Row >= 0 && Row < RCount && Ofs >= 0);
784     L = RLine(Row);
785 
786     if (Ofs < 0) return 0;
787     if (Ofs > L->Count) return 0;
788     if (ACount == 0) return 1;
789 
790     if (Modify() == 0) return 0;
791 
792 #ifdef CONFIG_UNDOREDO
793     if (BFI(this, BFI_Undo) == 1) {
794         if (PushULong(Row) == 0) return 0;
795         if (PushULong(Ofs) == 0) return 0;
796         if (PushULong(ACount) == 0) return 0;
797         if (PushUChar(ucInsChars) == 0) return 0;
798     }
799 #endif
800     if (L->Allocate(L->Count + ACount) == 0) return 0;
801     if (L->Count > Ofs)
802         memmove(L->Chars + Ofs + ACount, L->Chars + Ofs, L->Count - Ofs);
803     if (Buffer == 0)
804         memset(L->Chars + Ofs, ' ', ACount);
805     else
806         memmove(L->Chars + Ofs, Buffer, ACount);
807     L->Count += ACount;
808     Draw(Row, Row);
809     Hilit(Row);
810     // printf("OK\n");
811     return 1;
812 }
813 
UnTabPoint(int Row,int Col)814 int EBuffer::UnTabPoint(int Row, int Col) {
815     ELine *L;
816     int Ofs, Pos, TPos;
817 
818     assert(Row >= 0 && Row < RCount && Col >= 0);
819     L = RLine(Row);
820     Ofs = CharOffset(L, Col);
821     if (Ofs >= L->Count)
822         return 1;
823     if (L->Chars[Ofs] != '\t')
824         return 1;
825     Pos = ScreenPos(L, Ofs);
826     if (Pos < Col) {
827         TPos = NextTab(Pos, BFI(this, BFI_TabSize));
828         if (DelChars(Row, Ofs, 1) != 1)
829             return 0;
830         if (InsChars(Row, Ofs, TPos - Pos, 0) != 1)
831             return 0;
832     }
833     return 1;
834 }
835 
ChgChars(int Row,int Ofs,size_t ACount,const char *)836 int EBuffer::ChgChars(int Row, int Ofs, size_t ACount, const char * /*Buffer*/) {
837     PELine L;
838 
839     assert(Row >= 0 && Row < RCount && Ofs >= 0);
840     L = RLine(Row);
841 
842     if (Ofs < 0) return 0;
843     if (Ofs > L->Count) return 0;
844     if (ACount == 0) return 1;
845 
846     if (Modify() == 0) return 0;
847 
848 #ifdef CONFIG_UNDOREDO
849     if (BFI(this, BFI_Undo) == 1) {
850         if (PushUData(L->Chars + Ofs, ACount) == 0) return 0;
851         if (PushULong(ACount) == 0) return 0;
852         if (PushULong(Ofs) == 0) return 0;
853         if (PushULong(Row) == 0) return 0;
854         if (PushUChar(ucDelChars) == 0) return 0;
855         if (PushULong(Row) == 0) return 0;
856         if (PushULong(Ofs) == 0) return 0;
857         if (PushULong(ACount) == 0) return 0;
858         if (PushUChar(ucInsChars) == 0) return 0;
859     }
860 #endif
861     Hilit(Row);
862     Draw(Row, Row);
863     return 1;
864 }
865 
DelText(int Row,int Col,size_t ACount,int DoMark)866 int EBuffer::DelText(int Row, int Col, size_t ACount, int DoMark) {
867     int L, B, C;
868 
869 //    printf("DelTExt: %d:%d %d\n", Row, Col, ACount);
870 
871     assert(Row >= 0 && Row < RCount && Col >= 0);
872     if (Modify() == 0) return 0;
873 
874     if (ACount == 0) return 1;
875     L = LineLen(Row);
876     if (Col >= L)
877         return 1;
878     if (ACount == -1 || ACount + Col > L)
879         ACount = L - Col;
880     if (UnTabPoint(Row, Col) == 0)
881         return 0;
882     if (UnTabPoint(Row, Col + ACount) == 0)
883         return 0;
884     B = CharOffset(RLine(Row), Col);
885     C = CharOffset(RLine(Row), Col + ACount);
886     if ((ACount > 0) && (B != -1) && (C != -1)) {
887         if (DelChars(Row, B, C - B) == 0) return 0;
888         if (DoMark) UpdateMarker(umDelete, Row, Col, 0, ACount);
889     }
890 //    printf("OK\n");
891     return 1;
892 }
893 
InsText(int Row,int Col,size_t ACount,const char * ABuffer,int DoMark)894 int EBuffer::InsText(int Row, int Col, size_t ACount, const char *ABuffer, int DoMark) {
895     int B, L;
896 
897 //    printf("InsText: %d:%d %d\n", Row, Col, ACount);
898     assert(Row >= 0 && Row < RCount && Col >= 0);
899     if (ACount == 0) return 1;
900     if (Modify() == 0) return 0;
901 
902     if (DoMark) UpdateMarker(umInsert, Row, Col, 0, ACount);
903     L = LineLen(Row);
904     if (L < Col) {
905         if (InsChars(Row, RLine(Row)->Count, Col - L, 0) == 0)
906             return 0;
907     } else
908         if (UnTabPoint(Row, Col) == 0) return 0;
909     B = CharOffset(RLine(Row), Col);
910     if (InsChars(Row, B, ACount, ABuffer) == 0) return 0;
911 //    printf("OK\n");
912     return 1;
913 }
914 
PadLine(int Row,size_t Length)915 int EBuffer::PadLine(int Row, size_t Length) {
916     size_t L;
917 
918     L = LineLen(Row);
919     if (L < Length)
920         if (InsChars(Row, RLine(Row)->Count, Length - L, 0) == 0)
921             return 0;
922     return 1;
923 }
924 
InsLineText(int Row,int Col,size_t ACount,int LCol,PELine Line)925 int EBuffer::InsLineText(int Row, int Col, size_t ACount, int LCol, PELine Line) {
926     int Ofs, Pos, TPos, C, B, L;
927 
928     //fprintf(stderr, "\n\nInsLineText: %d:%d %d %d", Row, Col, ACount, LCol);
929     assert(Row >= 0 && Row < RCount && Col >= 0 && LCol >= 0);
930     if (BFI(this, BFI_ReadOnly) == 1)
931         return 0;
932 
933     L = ScreenPos(Line, Line->Count);
934     if (LCol >= L) return 1;
935     if (ACount == -1) ACount = L - LCol;
936     if (ACount + LCol > L) ACount = L - LCol;
937     if (ACount == 0) return 1;
938     assert(ACount > 0);
939 
940     B = Ofs = CharOffset(Line, LCol);
941     if (Ofs < Line->Count && Line->Chars[Ofs] == '\t') {
942         Pos = ScreenPos(Line, Ofs);
943         if (Pos < LCol) {
944             TPos = NextTab(Pos, BFI(this, BFI_TabSize));
945             if (InsText(Row, Col, TPos - LCol, 0) == 0)
946                 return 0;
947             Col += TPos - LCol;
948             ACount -= TPos - LCol;
949             LCol = TPos;
950             B++;
951         }
952     }
953     C = Ofs = CharOffset(Line, LCol + ACount);
954     if (Ofs < Line->Count && Line->Chars[Ofs] == '\t') {
955         Pos = ScreenPos(Line, Ofs);
956         if (Pos < LCol + ACount) {
957             if (InsText(Row, Col, LCol + ACount - Pos, 0) == 0)
958                 return 0;
959         }
960     }
961     //fprintf(stderr, "B = %d, C = %d\n", B, C);
962     C -= B;
963     if (C <= 0) return 1;
964     if (InsText(Row, Col, C, Line->Chars + B) == 0) return 0;
965 //    printf("OK\n");
966     return 1;
967 }
968 
SplitLine(int Row,int Col)969 int EBuffer::SplitLine(int Row, int Col) {
970     int VL;
971 
972     assert(Row >= 0 && Row < RCount && Col >= 0);
973 
974     if (BFI(this, BFI_ReadOnly) == 1) return 0;
975 
976     VL = RToV(Row);
977     if (VL == -1)
978         if (ExposeRow(Row) == 0) return 0;
979     if (Row > 0) {
980         VL = RToV(Row - 1);
981         if (VL == -1)
982             if (ExposeRow(Row - 1) == 0) return 0;
983     }
984     VL = RToV(Row);
985     assert(VL != -1);
986     if (Col == 0) {
987         if (InsLine(Row, 0, 1) == 0) return 0;
988     } else {
989         UpdateMarker(umSplitLine, Row, Col, 0, 0);
990         if (InsLine(Row, 1, 0) == 0) return 0;
991 #ifdef CONFIG_SYNTAX_HILIT
992 	RLine(Row)->StateE = short((Row > 0) ? RLine(Row - 1)->StateE : 0);
993 #endif
994         if (Col < LineLen(Row)) {
995             int P, L;
996             //if (RLine(Row)->ExpandTabs(Col, -2, &Flags) == 0) return 0;
997             if (UnTabPoint(Row, Col) != 1)
998                 return 0;
999 
1000             P = CharOffset(RLine(Row), Col);
1001             L = LineLen(Row);
1002 
1003             if (InsText(Row + 1, 0, RLine(Row)->Count - P, RLine(Row)->Chars + P, 0) == 0) return 0;
1004             if (DelText(Row, Col, L - Col, 0) == 0) return 0;
1005         }
1006     }
1007     Draw(Row, -1);
1008     Hilit(Row);
1009     return 1;
1010 }
1011 
JoinLine(int Row,int Col)1012 int EBuffer::JoinLine(int Row, int Col) {
1013     int Len, VLine;
1014 
1015     if (BFI(this, BFI_ReadOnly) == 1) return 0;
1016     if (Row < 0 || Row >= RCount - 1) return 0;
1017     if (Col < 0) return 0;
1018     Len = LineLen(Row);
1019     if (Col < Len) Col = Len;
1020     VLine = RToV(Row);
1021     if (VLine == -1) {
1022         if (ExposeRow(Row) == 0) return 0;
1023         if (ExposeRow(Row + 1) == 0) return 0;
1024     }
1025     VLine = RToV(Row);
1026     if (Col == 0 && RLine(Row)->Count == 0) {
1027         if (DelLine(Row, 1) == 0) return 0;
1028     } else {
1029         if (InsText(Row, Col, RLine(Row + 1)->Count, RLine(Row + 1)->Chars, 0) == 0) return 0;
1030         if (DelLine(Row + 1, 0) == 0) return 0;
1031         UpdateMarker(umJoinLine, Row, Col, 0, 0);
1032     }
1033     Draw(Row, -1);
1034     Hilit(Row);
1035     return 1;
1036 }
1037