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