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