1 
2 //  ------------------------------------------------------------------
3 //  GoldED+
4 //  Copyright (C) 1990-1999 Odinn Sorensen
5 //  Copyright (C) 1999-2000 Alexander S. Aganichev
6 //  ------------------------------------------------------------------
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License as
9 //  published by the Free Software Foundation; either version 2 of the
10 //  License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 //  MA 02111-1307 USA
21 //  ------------------------------------------------------------------
22 //  $Id: geedit2.cpp,v 1.40 2011/02/22 16:18:21 stas_degteff Exp $
23 //  ------------------------------------------------------------------
24 //  The Internal Editor (IE), part 2.
25 //  ------------------------------------------------------------------
26 
27 #include <golded.h>
28 #include <geedit.h>
29 #include <gutlcode.h>
30 #include <gutlclip.h>
31 
32 #if defined(__USE_ALLOCA__)
33 #include <malloc.h>
34 #endif
35 
36 
37 //  ------------------------------------------------------------------
38 //  Constructor
39 
IEclass(int __scol,int __ecol,int __srow,int __erow,int __border)40 IEclass::IEclass(int __scol, int __ecol, int __srow, int __erow, int __border) {
41 
42   win_mincol = __scol;
43   win_minrow = __srow;
44   win_maxcol = __ecol;
45   win_maxrow = __erow;
46   win_border = __border;
47 
48   win_hasborder = (win_border == 5) ? 0 : 1;
49 
50   mincol  = 0;
51   minrow  = 0;
52   maxcol  = win_maxcol - win_mincol - (2*win_hasborder);
53   maxrow  = win_maxrow - win_minrow - (2*win_hasborder);
54 
55   col  = 0;
56   row  = 0;
57   ccol = 0;
58   crow = 0;
59 
60   chartyped    = false;
61   currline     = NULL;
62   done         = NO;
63   insert       = YES;
64   drawlines    = 0;
65   drawflag     = true;
66   marginquotes = 0;
67   margintext   = 0;
68   msgmode      = 0;
69   msgptr       = NULL;
70   quitnow      = NO;
71   thisrow      = 0;
72   unfinished   = "+$!$+ GoldED Internal Editor: Unfinished Message!";
73   blockcol     = -1;
74   selecting    = NO;
75 
76   throw_new(Undo = new UndoStack(this));
77   windowopen();
78 }
79 
80 
81 //  ------------------------------------------------------------------
82 //  Destructor
83 
~IEclass()84 IEclass::~IEclass() {
85 
86   throw_delete(Undo);
87   windowclose();
88 }
89 
90 
91 //  ------------------------------------------------------------------
92 
windowopen()93 void IEclass::windowopen() {
94 
95   // Open editor window without clearing the window area
96   #define STYLE_NOCLEAR -1
97   int _tmp = gwin.style;
98   gwin.style = STYLE_NOCLEAR;
99   editwin.open(win_minrow, win_mincol, win_maxrow, win_maxcol, 5, C_READB, C_READW, C_READPB);
100   gwin.style = _tmp;
101   whelppcat(H_Editor);
102 }
103 
104 
105 //  ------------------------------------------------------------------
106 
windowclose()107 void IEclass::windowclose() {
108 
109   whelpop();
110   // Close editor window without removing the window itself
111   editwin.unlink();
112 }
113 
114 
115 //  ------------------------------------------------------------------
116 
Edit__killpastebuf()117 void Edit__killpastebuf() {
118 
119   while(Edit__pastebuf) {
120     if(Edit__pastebuf->next) {
121       Edit__pastebuf = Edit__pastebuf->next;
122       throw_xdelete(Edit__pastebuf->prev);
123     }
124     else
125       throw_xdelete(Edit__pastebuf);
126   }
127 }
128 
129 
130 //  ------------------------------------------------------------------
131 
Edit__killkillbuf()132 void Edit__killkillbuf() {
133 
134   while(Edit__killbuf) {
135     if(Edit__killbuf->prev) {
136       Edit__killbuf = Edit__killbuf->prev;
137       throw_xdelete(Edit__killbuf->next);
138     }
139     else
140       throw_xdelete(Edit__killbuf);
141   }
142 }
143 
144 
145 //  ------------------------------------------------------------------
146 
killkillbuf()147 void IEclass::killkillbuf() {
148 
149   while(Edit__killbuf) {
150     if(Undo->FixPushLine(Edit__killbuf)) {
151       if(Edit__killbuf->prev) {
152         Edit__killbuf = Edit__killbuf->prev;
153         Edit__killbuf->next = NULL;
154       }
155       else {
156         Edit__killbuf = NULL;
157       }
158     }
159     else {
160       if(Edit__killbuf->prev) {
161         Edit__killbuf = Edit__killbuf->prev;
162         throw_xdelete(Edit__killbuf->next);
163       }
164       else
165         throw_xdelete(Edit__killbuf);
166     }
167   }
168 }
169 
170 
171 //  ------------------------------------------------------------------
172 
FreePastebuf()173 void FreePastebuf() {
174 
175   Edit__killpastebuf();
176   Edit__killkillbuf();
177 }
178 
179 
180 //  ------------------------------------------------------------------
181 
ClearDeleteBuf()182 void IEclass::ClearDeleteBuf() {
183 
184   GFTRK("EditClearDeleteBuf");
185 
186   killkillbuf();
187   HandleGEvent(EVTT_JOBDONE);
188 
189   GFTRK(0);
190 }
191 
192 
193 //  ------------------------------------------------------------------
194 
ClearPasteBuf()195 void IEclass::ClearPasteBuf() {
196 
197   GFTRK("EditClearPasteBuf");
198 
199   killpastebuf();
200   HandleGEvent(EVTT_JOBDONE);
201 
202   GFTRK(0);
203 }
204 
205 
206 //  ------------------------------------------------------------------
207 
GoBegLine()208 void IEclass::GoBegLine() {
209 
210   GFTRK("EditGoBegLine");
211 
212   col = mincol;
213 
214   if(blockcol != -1)
215     displine(currline, row);
216 
217   GFTRK(0);
218 }
219 
220 
221 //  ------------------------------------------------------------------
222 
DelLtWord()223 void IEclass::DelLtWord() {
224 
225   GFTRK("EditDelLtWord");
226 
227   if(col == 0) {
228     DelLeft();
229     GFTRK(0);
230     return;
231   }
232 
233   int _ptr, _ptr2;
234   _ptr = _ptr2 = col;
235   _ptr--;
236 
237   // test test test test     test test test test
238   // test test test test ,   test test test test
239   // test test test test ,,  test test test test
240 
241   if(currline->txt[_ptr] == ' ') {
242     while((currline->txt[_ptr] == ' ') and (_ptr > 0))
243       _ptr--;
244     if(currline->txt[_ptr] != ' ')
245       _ptr++;
246   }
247   else if(isxalnum(currline->txt[_ptr])) {
248     while(isxalnum(currline->txt[_ptr]) and (_ptr > 0))
249       _ptr--;
250     while((currline->txt[_ptr] == ' ') and (_ptr > 0))
251       _ptr--;
252     if((currline->txt[_ptr] != ' ') and (_ptr > 0))
253       _ptr++;
254   }
255   else {
256     DelLeft();
257     GFTRK(0);
258     return;
259   }
260 
261   col -= _ptr2-_ptr;
262 
263   Undo->PushItem(EDIT_UNDO_DEL_TEXT, currline, col, _ptr2-_ptr);
264   currline->txt.erase(_ptr, _ptr2-_ptr);
265 
266   wrapdel(&currline, &col, &row);
267 
268   GFTRK(0);
269 }
270 
271 
272 //  ------------------------------------------------------------------
273 
DelRtWord()274 void IEclass::DelRtWord() {
275 
276   GFTRK("EditDelRtWord");
277 
278   if((currline->txt.length() == col+1) or (currline->txt[col+1] == '\n')) {
279     DelChar();
280     GFTRK(0);
281     return;
282   }
283 
284   int _ptr, _ptr2;
285   _ptr = _ptr2 = col;
286 
287   // test test test test,   test test test test
288   // test test test test,   test test test test
289 
290   if(currline->txt[_ptr] == ' ') {
291     while(_ptr != currline->txt.length() and currline->txt[_ptr] == ' ')
292       _ptr++;
293   }
294   else if(isxalnum(currline->txt[_ptr])) {
295     // Delete word
296     while(_ptr != currline->txt.length() and isxalnum(currline->txt[_ptr]))
297       _ptr++;
298     // Delete spaces after word
299     while(_ptr != currline->txt.length() and currline->txt[_ptr] == ' ')
300       _ptr++;
301   }
302   else {
303     DelChar();
304     GFTRK(0);
305     return;
306   }
307 
308   Undo->PushItem(EDIT_UNDO_DEL_TEXT, currline, col, _ptr-_ptr2);
309   currline->txt.erase(_ptr2, _ptr-_ptr2);
310 
311   wrapdel(&currline, &col, &row);
312 
313   GFTRK(0);
314 }
315 
316 
317 //  ------------------------------------------------------------------
318 
GoTopMsg()319 void IEclass::GoTopMsg() {
320 
321   GFTRK("EditGoTopMsg");
322 
323   currline = findfirstline();
324   col = mincol;
325   row = minrow;
326   thisrow = 0;
327   refresh(currline, minrow);
328 
329   GFTRK(0);
330 }
331 
332 
333 //  ------------------------------------------------------------------
334 
GoBotMsg()335 void IEclass::GoBotMsg() {
336 
337   GFTRK("EditGoBotMsg");
338 
339   col = mincol;
340   thisrow = 0;
341   currline = findfirstline();
342 
343   // Go to the last line in the msg
344   while(currline->next) {
345     currline = currline->next;
346     thisrow++;
347   }
348 
349   // Pointer to the line to display at the top of the window
350   Line* _topline = currline;
351 
352   // The new cursor row
353   row = MinV(thisrow, maxrow);
354 
355   // How many lines to go back to get the top line
356   int _count = row;
357 
358   // Go back to get the top line
359   while(_count-- and _topline->prev)
360     _topline = _topline->prev;
361 
362   // Refresh the display
363   refresh(_topline, minrow);
364 
365   GFTRK(0);
366 }
367 
368 
369 //  ------------------------------------------------------------------
370 
GoTopLine()371 void IEclass::GoTopLine() {
372 
373   GFTRK("EditGoTopLine");
374 
375   int _count = row;
376 
377   while(_count-- and currline->prev) {
378     currline = currline->prev;
379     thisrow--;
380   }
381 
382   col = mincol;
383   row = minrow;
384 
385   if(blockcol != -1)
386     refresh(currline, minrow);
387 
388   GFTRK(0);
389 }
390 
391 
392 //  ------------------------------------------------------------------
393 
GoBotLine()394 void IEclass::GoBotLine() {
395 
396   GFTRK("EditGoBotLine");
397 
398   Line *_oldcurrline = currline;
399   int  _oldrow = row;
400 
401   while((row < maxrow) and currline->next) {
402     currline = currline->next;
403     thisrow++;
404     row++;
405   }
406 
407   col = mincol;
408 
409   if(blockcol != -1)
410     refresh(_oldcurrline, _oldrow);
411 
412   GFTRK(0);
413 }
414 
415 
416 //  ------------------------------------------------------------------
417 
findanchor()418 Line* IEclass::findanchor() {
419 
420   GFTRK("Editfindanchor");
421 
422   // Rewind to the first line
423   Line* _anchor = findfirstline();
424 
425   // Search all lines to find the anchor (a line with a block mark)
426   while(not (_anchor->type & GLINE_BLOK) and _anchor->next)
427     _anchor = _anchor->next;
428 
429   GFTRK(0);
430 
431   // Return pointer to the anchor line or NULL if no anchor was found
432   return (_anchor->type & GLINE_BLOK) ? _anchor : (Line*)NULL;
433 }
434 
435 
436 //  ------------------------------------------------------------------
437 
BlockAnchor()438 void IEclass::BlockAnchor() {
439 
440   GFTRK("EditBlockAnchor");
441 
442   Line* _anchor = findanchor();
443 
444   // Is there an anchor already?
445   if(_anchor) {
446 
447     // Yes, so replace it with the current line
448 
449     // Remove block mark
450     _anchor->type &= ~GLINE_BLOK;
451     blockcol = -1;
452 
453     // Is the old anchor different from the current line?
454     if(_anchor != currline) {
455 
456       // Set the new anchor
457       _anchor = currline;
458       _anchor->type |= GLINE_BLOK;
459       blockcol = col;
460 
461       // Find the line at the top
462       Line* _topline = findtopline();
463 
464       // Refresh display to remove the block color on the old anchor line
465       // Just in case the old anchor line is visible
466       refresh(_topline, minrow);
467     }
468 
469     // Remove the old contents of the paste buffer
470     killpastebuf();
471   }
472   else {
473 
474     for(Line* _line = findfirstline(); _line; _line = _line->next)
475       _line->type &= ~GLINE_BLOK;
476 
477     // There was no anchor, so mark the current line as the new anchor
478     currline->type |= GLINE_BLOK;
479     blockcol = col;
480 
481     // Refresh the display
482     Line* _topline = findtopline();
483     refresh(_topline, minrow);
484   }
485 
486   displine(currline, row);
487 
488   GFTRK(0);
489 }
490 
491 
492 //  ------------------------------------------------------------------
493 
BlockCopy()494 void IEclass::BlockCopy() {
495 
496   GFTRK("EditBlockCopy");
497 
498   // Find the anchor, if any
499   Line* _anchor = findanchor();
500 
501   // Did we find the anchor?
502   if(_anchor) {
503 
504     Line* _firstcopyline = currline;
505     Line* _lastcopyline  = currline;
506     int   firstcol = col, lastcol = col;
507 
508     // Search below to find the anchor line
509     while(_lastcopyline->next and (_lastcopyline != _anchor))
510       _lastcopyline = _lastcopyline->next;
511 
512     // Was the anchor line above or on the current line?
513     if(_lastcopyline != _anchor) {
514 
515       // The last copy line is the current line
516       _lastcopyline = currline;
517 
518       // Search above to find the anchor line
519       while(_firstcopyline->prev and (_firstcopyline != _anchor))
520         _firstcopyline = _firstcopyline->prev;
521       firstcol = blockcol;
522     }
523     else {
524       if(currline != _anchor or blockcol > col)
525         lastcol = blockcol;
526       else
527         firstcol = blockcol;
528     }
529 
530     // The _firstcopyline and _lastcopyline pointers
531     // are now pointing where they should
532 
533     // Remove the old paste buffer
534     killpastebuf();
535 
536     // Pointer to the previous line in the paste buffer
537     Line* _prevline = NULL;
538 
539     // Copy lines to the paste buffer
540     while(1) {
541 
542       // Allocate a new line
543       Line* _copyline;
544 
545       // Copy text and type
546       if(_prevline == NULL)
547         _copyline = new Line(_firstcopyline->txt.c_str() + firstcol);
548       else
549         _copyline = new Line(_firstcopyline->txt.c_str());
550       throw_xnew(_copyline);
551       if(_firstcopyline == _lastcopyline) {
552         if(_prevline)
553           _copyline->txt.erase(lastcol);
554         else
555           _copyline->txt.erase(lastcol-firstcol);
556       }
557       _copyline->type = _firstcopyline->type & ~GLINE_BLOK;
558 
559       // Link in the new line
560       _copyline->prev = _prevline;
561       if(_prevline)
562         _prevline->next = _copyline;
563       _copyline->next = NULL;
564 
565       // Point the paste buffer to the first line of the copy
566       if(Edit__pastebuf == NULL)
567         Edit__pastebuf = _copyline;
568 
569       // Break out of the loop if the last line was copied
570       if(_firstcopyline == _lastcopyline)
571         break;
572 
573       // Keep pointer to the new line
574       _prevline = _copyline;
575 
576       // Continue with the next line
577       _firstcopyline = _firstcopyline->next;
578     }
579 
580     selecting = NO;
581     blockcol = -1;
582     for(Line* _line = findfirstline(); _line; _line = _line->next)
583       _line->type &= ~GLINE_BLOK;
584 
585     // Refresh display to remove the block color
586     Line* _topline = findtopline();
587     refresh(_topline, minrow);
588 
589     Buf2Clip();
590   }
591   killpastebuf();
592 
593   GFTRK(0);
594 }
595 
596 
597 //  ------------------------------------------------------------------
598 
BlockDel(Line * anchor)599 void IEclass::BlockDel(Line* anchor) {
600 
601   GFTRK("EditBlockDel");
602 
603   Line* firstcutline = currline;
604   Line* lastcutline  = currline;
605   uint firstcutlinerow = row;
606   uint lastcutlinerow  = row;
607   int  firstcol = col, lastcol = col;
608 
609   // Search below to find the anchor line
610   while(lastcutline->next and (lastcutline != anchor)) {
611     lastcutline = lastcutline->next;
612     lastcutlinerow++;
613   }
614 
615   // Was the anchor line above or on the current line?
616   if(lastcutline != anchor) {
617 
618     // The last cut line is the current line
619     lastcutline = currline;
620     lastcutlinerow = row;
621 
622     // Search above to find the anchor line
623     while(firstcutline->prev and (firstcutline != anchor)) {
624       firstcutline = firstcutline->prev;
625       if(firstcutlinerow)
626         firstcutlinerow--;
627     }
628     firstcol = blockcol;
629   }
630   else {
631     if((currline != anchor) or (blockcol > col))
632       lastcol = blockcol;
633     else
634       firstcol = blockcol;
635   }
636 
637   // The firstcutline and lastcutline pointers
638   // are now pointing where they should
639 
640   if(firstcutline != lastcutline) {
641     size_t __len = firstcutline->txt.length();
642     firstcutline->txt += lastcutline->txt.c_str()+lastcol;
643 
644     // We need to set up prow to prevent cosmetic bugs
645     uint __prow = prow;
646     getthisrow(firstcutline);
647     prow = thisrow;
648     getthisrow(currline);
649     Undo->PushItem(EDIT_UNDO_INS_TEXT, firstcutline, __len);
650     prow = __prow;
651 
652     Undo->PushItem(EDIT_UNDO_DEL_TEXT|BATCH_MODE, firstcutline, firstcol, __len-firstcol);
653     firstcutline->txt.erase(firstcol, __len-firstcol);
654   }
655   else {
656     Undo->PushItem(EDIT_UNDO_DEL_TEXT, firstcutline, firstcol, lastcol-firstcol);
657     firstcutline->txt.erase(firstcol, lastcol-firstcol);
658   }
659   setlinetype(firstcutline);
660   firstcutline->type &= ~GLINE_BLOK;
661   blockcol = -1;
662   currline = firstcutline;
663   row = firstcutlinerow;
664   col = firstcol;
665   if(firstcutline != lastcutline) {
666     do {
667       Undo->PushItem(EDIT_UNDO_DEL_LINE|BATCH_MODE, firstcutline = firstcutline->next);
668     } while(firstcutline != lastcutline);
669 
670     currline->next = lastcutline->next;
671     if(lastcutline->next)
672       lastcutline->next->prev = currline;
673   }
674 
675   // Refresh the display
676   if(not RngV(row, minrow, maxrow)) {
677     row = minrow;
678     wrapdel(&currline, &col, &row, false);
679     refresh(currline, minrow);
680   }
681   else {
682     row = MaxV(firstcutlinerow, minrow);
683     Line* topline = findtopline();
684     wrapdel(&currline, &col, &row, false);
685     refresh(topline, minrow);
686   }
687 
688   Line* line;
689   for(line = findfirstline(); line; line = line->next)
690     line->type &= ~GLINE_BLOK;
691 
692   selecting = NO;
693 
694   GFTRK(0);
695 }
696 
697 
698 //  ------------------------------------------------------------------
699 
BlockCut(bool just_delete)700 void IEclass::BlockCut(bool just_delete) {
701 
702   GFTRK("EditBlockCut");
703 
704   // Find the anchor, if any
705   Line* _anchor = findanchor();
706 
707   // Did we find the anchor?
708   if(_anchor) {
709 
710     int _blockcol = blockcol;
711 
712     if(not just_delete)
713       BlockCopy();
714 
715     blockcol = _blockcol;
716 
717     BlockDel(_anchor);
718   }
719   else
720     killpastebuf();
721 
722   GFTRK(0);
723 }
724 
725 
726 //  ------------------------------------------------------------------
727 
BlockPaste()728 void IEclass::BlockPaste() {
729 
730   GFTRK("EditBlockPaste");
731 
732   killpastebuf();
733   Clip2Buf();
734 
735   if(Edit__pastebuf) {
736 
737     Line* _pasteline = Edit__pastebuf;
738 
739     if(not batch_mode)
740       Undo->PushItem(EDIT_UNDO_VOID);
741 
742     // For each of the lines in the paste buffer
743     while(_pasteline) {
744 
745       uint  curlen = currline->txt.length();
746       uint  pastelen = _pasteline->txt.length();
747 
748       if(col > curlen)
749         col = curlen;
750 
751       if(_pasteline->txt.find('\n') != _pasteline->txt.npos) {
752         // append to current line
753         Undo->PushItem(EDIT_UNDO_DEL_TEXT|BATCH_MODE, currline, col);
754         Line* _newline = insertlinebelow(currline, currline->txt.c_str()+col, BATCH_MODE);
755         currline->txt.erase(col);
756         currline->txt += _pasteline->txt;
757         Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, currline, col, pastelen);
758         setlinetype(currline);
759         col = currline->txt.length();
760         wrapins(&currline, &col, &row, false);
761         currline = _newline;
762         col = 0;
763         if(row < maxrow)
764           row++;
765       }
766       else {
767         // insert into current line
768         currline->txt.insert(col, _pasteline->txt);
769         Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, currline, col, pastelen);
770         col += pastelen;
771         wrapins(&currline, &col, &row, false);
772       }
773 
774       setlinetype(currline);
775 
776       // Continue with the next line in the paste buffer
777       _pasteline = _pasteline->next;
778     }
779 
780     selecting = NO;
781     blockcol = -1;
782     for(Line* _line = findfirstline(); _line; _line = _line->next)
783       _line->type &= ~GLINE_BLOK;
784 
785     // Refresh the display
786     Line* _topline = findtopline();
787     refresh(_topline, minrow);
788   }
789 
790   GFTRK(0);
791 }
792 
793 
794 //  ------------------------------------------------------------------
795 
LoadFile()796 void IEclass::LoadFile() {
797 
798   GFTRK("EditLoadFile");
799 
800   // Open the file to load
801   gfile _fp(AddPath(CFG->goldpath, EDIT->File()), "rb", CFG->sharemode);
802   if (_fp.isopen())
803   {
804     XlatName __oldxlatimport;
805 
806     // Pop up a wait window
807     cursoroff();
808     w_info(LNG->Wait);
809 
810     throw_delete(Undo);
811 
812     // Find the first line
813     Line* _line = findfirstline();
814 
815     // Remove all lines
816     while(_line) {
817       Line* _nextline = _line->next;
818       throw_xdelete(_line);
819       _line = _nextline;
820     }
821 
822     // Remove message text and reset pointers
823     throw_release(msgptr->txt);
824     currline = msgptr->lin = NULL;
825 
826     // Allocate space for new message text
827     msgptr->txt = (char*)throw_calloc(1, (uint)(_fp.FileLength()+256));
828 
829     // Eat the backup marking line
830     char _buf[EDIT_BUFLEN];
831     _fp.Fgets(_buf, sizeof(_buf));
832     if (not striinc(unfinished, _buf))
833       _fp.Rewind();
834 
835     // Load the file and close it
836     _fp.Fread(msgptr->txt, (uint)_fp.FileLength());
837     _fp.Fclose();
838 
839     // Save current charset
840     strcpy(__oldxlatimport, AA->Xlatimport());
841     AA->SetXlatimport(CFG->xlatlocalset);
842 
843     // Index message text
844     msgptr->TextToLines(margintext-1, false);
845     _line = currline = msgptr->lin;
846 
847     // Restore charset
848     AA->SetXlatimport(__oldxlatimport);
849 
850     // Change lines to internal editor format
851     while(_line) {
852       strtrim(_line->txt);
853       if(_line->type & GLINE_HARD)
854         _line->txt += "\n";
855       else
856         _line->txt += " ";
857       _line = _line->next;
858     }
859 
860     // Remove the wait window
861     w_info(NULL);
862 
863     // Display the loaded message
864     Line* l = findfirstline();
865     uint i;
866 
867     for(i=0; l->next and i<thisrow-row; i++)
868       l = l->next;
869 
870     refresh(l, minrow);
871 
872     for(i=0; l->next and i<row; i++)
873       l = l->next;
874 
875     if(l->next == NULL)
876       row = i;
877     currline = l;
878     col = mincol;
879 
880     throw_new(Undo = new UndoStack(this));
881   }
882 
883   GFTRK(0);
884 }
885 
886 
887 //  ------------------------------------------------------------------
888 
uuencode_enc(int c)889 inline char uuencode_enc(int c) { return (char)(c ? (c & 077) + ' ': '`'); }
890 
editimport(Line * __line,char * __filename,bool imptxt)891 void IEclass::editimport(Line* __line, char* __filename, bool imptxt) {
892 
893   XlatName __oldxlatimport;
894 
895   GFTRK("Editimport");
896 
897   // Save the unfinished msg first of all
898   savefile(MODE_UPDATE);
899 
900   update_statusline(LNG->ImportFile);
901 
902   // Set initial import filename or wildcards
903   if(__filename) {
904     AA->SetInputfile(__filename);
905   }
906   else {
907     if(*AA->Inputfile() == NUL)
908       AA->SetInputfile("*");
909   }
910 
911   strcpy(__oldxlatimport, AA->Xlatimport());
912   AA->SetXlatimport(CFG->xlatlocalset);
913 
914   strcpy(CFG->inputfile, AA->Inputfile());
915 
916   int ImportMode;
917 
918   if(imptxt)
919     ImportMode = 0;
920   else {
921 
922     GMenuImportTxt MenuImportTxt;
923 
924     ImportMode = MenuImportTxt.Run();
925   }
926 
927   std::string filenamebuf;
928   Path tmpfile;
929   bool isPipe = NO;
930   bool fileselected = false;
931 
932   // Should the imported text be quoted or uuencoded?
933   #define quoteit    (ImportMode == 1)
934   #define uuencode   (ImportMode == 2)
935   #define base64     (ImportMode == 3)
936   #define getclip    (ImportMode == 4)
937   #define binary     (uuencode or base64)
938 
939   if(in_range(ImportMode, 0, 3) and edit_pathname(CFG->inputfile, sizeof(Path), LNG->ImportWhichFile, H_ImportFile)) {
940 
941     AA->SetInputfile(CFG->inputfile);
942 
943     // Pointer to the filename string
944     filenamebuf = AA->Inputfile();
945 
946     if(filenamebuf.c_str()[0] == '|'){
947       Path cmdline;
948 
949       if( not ((*CFG->temppath == NUL ) or is_dir(CFG->temppath)) )
950       {
951         w_info(LNG->TMPinvalidpath);
952         SayBibi();
953         waitkeyt(10000);
954         w_info("");
955         AA->SetXlatimport(__oldxlatimport);
956         GFTRK(0);
957         return;
958       }
959 
960       isPipe = YES;
961       mktemp(strxcpy(tmpfile, AddPath(CFG->temppath, "GIXXXXXX"), sizeof(Path)));
962       strxmerge(cmdline, sizeof(Path), filenamebuf.c_str()+1, " > ", tmpfile, NULL);
963       ShellToDos(cmdline, "", BLACK_|_BLACK, NO);
964       filenamebuf = tmpfile;
965       fileselected = true;
966     } else {
967       // Check for wildcards
968       // Is the filename a directory?
969       if(is_dir(filenamebuf)) {
970 
971         // Does the filename contain wildcards?
972         if(not strpbrk(filenamebuf.c_str(), "*?")) {
973 
974           // Add match-all wildcards
975           AddBackslash(filenamebuf);
976           filenamebuf += "*";
977         }
978       }
979 
980       fileselected = true;
981 
982       // Does the filename contain wildcards?
983       if(strpbrk(filenamebuf.c_str(), "*?")) {
984 
985         // Set selection window title and statusline
986         set_title(LNG->ImportTitle, TCENTER, C_MENUT);
987         update_statuslinef(LNG->ImportStatus, "ST_IMPORTSTATUS", filenamebuf.c_str());
988 
989         // Start the file picker
990         fileselected = wpickfile(win_minrow, win_mincol, win_maxrow, win_maxcol, W_BMENU, C_MENUB, C_MENUW, C_MENUS, NO, filenamebuf, maketitle_and_status);
991       }
992     }
993   }
994 
995   if (fileselected or getclip)
996   {
997     // Open the file/clipboard
998     gfile fp;
999     gclipbrd clipbrd;
1000 
1001     if(getclip)
1002       filenamebuf = CLIP_NAME;
1003 
1004     if(getclip ? clipbrd.openread() :
1005        (fp.Fopen(filenamebuf.c_str(), binary ? "rb" : "rt", CFG->sharemode))!=NULL)
1006     {
1007       if (isPipe)
1008         filenamebuf = AA->Inputfile();
1009 
1010       const char *imp_filename = (getclip or isPipe) ? filenamebuf.c_str() : CleanFilename(filenamebuf.c_str());
1011 
1012       // we need to truncate filename to prevent unpredictable results
1013       int delta = strlen(imp_filename) - margintext;
1014       if(delta > 0) {
1015         filenamebuf.erase(filenamebuf.length()-delta);
1016         imp_filename = (getclip or isPipe) ? filenamebuf.c_str() : CleanFilename(filenamebuf.c_str());
1017       }
1018 
1019       update_statuslinef(LNG->ImportStatus, "ST_IMPORTSTATUS", filenamebuf.c_str());
1020 
1021       // Allocate paragraph read buffer
1022       char* _parabuf = (char*)throw_malloc(EDIT_PARABUFLEN);
1023 
1024       if(__line->prev)
1025         Undo->PushItem(EDIT_UNDO_VOID|PREV_LINE|batch_mode, __line->prev);
1026       else
1027         Undo->PushItem(EDIT_UNDO_VOID|batch_mode, __line);
1028       batch_mode = BATCH_MODE;
1029 
1030       // Add import begin text, if any
1031       if (*CFG->importbegin)
1032       {
1033         sprintf(_parabuf, "%s\n", CFG->importbegin);
1034         strischg(_parabuf, "@file", imp_filename);
1035         TokenXlat(MODE_NEW, _parabuf, EDIT_PARABUFLEN, true, msgptr, msgptr, CurrArea);
1036         _parabuf[strlen(_parabuf)-1] = '\n';
1037         _parabuf[margintext] = NUL;
1038         _parabuf[margintext-1] = '\n';
1039         __line = insertlinebelow(__line, _parabuf);
1040         setlinetype(__line);
1041       }
1042 
1043       if(uuencode) {
1044 
1045         sprintf(_parabuf, "begin 644 %s\n", imp_filename);
1046         _parabuf[margintext] = NUL;
1047         _parabuf[margintext-1] = '\n';
1048         __line = insertlinebelow(__line, _parabuf);
1049         setlinetype(__line);
1050 
1051         while (true)
1052         {
1053           char ibuf[80];
1054           char* iptr = ibuf;
1055           char* optr = _parabuf;
1056           int n = fp.Fread(ibuf, 1, 45);
1057           if (n < 45) memset(ibuf+n, 0, 45-n);
1058           *optr++ = uuencode_enc(n);
1059 
1060           for(int i=0; i<n; i+=3,iptr+=3) {
1061             *optr++ = uuencode_enc(*iptr >> 2);
1062             *optr++ = uuencode_enc(((*iptr << 4) & 060) | ((iptr[1] >> 4) & 017));
1063             *optr++ = uuencode_enc(((iptr[1] << 2) & 074) | ((iptr[2] >> 6) & 03));
1064             *optr++ = uuencode_enc(iptr[2] & 077);
1065           }
1066           *optr++ = '\n';
1067           *optr = NUL;
1068           __line = insertlinebelow(__line, _parabuf);
1069           // set type to text
1070           __line->type &= ~GLINE_ALL;
1071           if(n <= 0)
1072             break;
1073         }
1074 
1075         __line = insertlinebelow(__line, "end\n");
1076         setlinetype(__line);
1077       }
1078       else if(base64) {
1079 
1080         base64_engine b64;
1081 
1082         sprintf(_parabuf, "Content-type: application/octet-stream; name=\"%s\"\n", imp_filename);
1083         strcpy(_parabuf+margintext-2, "\"\n");
1084         __line = insertlinebelow(__line, _parabuf);
1085         setlinetype(__line);
1086         sprintf(_parabuf, "Content-transfer-encoding: base64\n");
1087         __line = insertlinebelow(__line, _parabuf);
1088         setlinetype(__line);
1089 
1090         sprintf(_parabuf, "\n");
1091         __line = insertlinebelow(__line, _parabuf);
1092         setlinetype(__line);
1093 
1094         while (true)
1095         {
1096           char ibuf[80];
1097           char* optr = _parabuf;
1098           int n = fp.Fread(ibuf, 1, 54);
1099           optr = b64.encode(optr, ibuf, n);
1100           *optr++ = '\n';
1101           *optr = NUL;
1102           __line = insertlinebelow(__line, _parabuf);
1103           setlinetype(__line);
1104           if(n <= 0)
1105             break;
1106         }
1107       }
1108       else {
1109 
1110         int tabsz = CFG->disptabsize ? CFG->disptabsize : 1;
1111 #if defined(__USE_ALLOCA__)
1112         char *spaces = (char*)alloca(tabsz+1);
1113 #else
1114         __extension__ char spaces[tabsz+1];
1115 #endif
1116         memset(spaces, ' ', tabsz);
1117         spaces[tabsz] = NUL;
1118         int level = LoadCharset(AA->Xlatimport(), CFG->xlatlocalset);
1119         size_t buf_len = EDIT_PARABUFLEN;
1120         char* buf = (char*) throw_malloc(EDIT_PARABUFLEN);
1121         Line* saveline = __line->next;
1122         __line->next = NULL;
1123 
1124         // Read paragraphs
1125         while (getclip ? clipbrd.read(_parabuf, EDIT_PARABUFLEN-7) : fp.Fgets(_parabuf, EDIT_PARABUFLEN-7))
1126         {
1127           XlatStr(buf, _parabuf, level, CharTable);
1128 
1129           // Insert a quotestring if asked
1130           if(quoteit)
1131             strins(" > ", buf, 0);
1132           else {
1133             // Invalidate tearline
1134             if(not CFG->invalidate.tearline.first.empty())
1135               doinvalidate(buf, CFG->invalidate.tearline.first.c_str(), CFG->invalidate.tearline.second.c_str(), true);
1136 
1137             // Invalidate originline
1138             if(not CFG->invalidate.origin.first.empty())
1139               doinvalidate(buf, CFG->invalidate.origin.first.c_str(), CFG->invalidate.origin.second.c_str());
1140 
1141             // Invalidate SEEN-BY's
1142             if(not CFG->invalidate.seenby.first.empty())
1143               doinvalidate(buf, CFG->invalidate.seenby.first.c_str(), CFG->invalidate.seenby.second.c_str());
1144 
1145             // Invalidate CC's
1146             if(not CFG->invalidate.cc.first.empty())
1147               doinvalidate(buf, CFG->invalidate.cc.first.c_str(), CFG->invalidate.cc.second.c_str());
1148 
1149             // Invalidate XC's
1150             if(not CFG->invalidate.xc.first.empty())
1151               doinvalidate(buf, CFG->invalidate.xc.first.c_str(), CFG->invalidate.xc.second.c_str());
1152 
1153             // Invalidate XP's
1154             if(not CFG->invalidate.xp.first.empty())
1155               doinvalidate(buf, CFG->invalidate.xp.first.c_str(), CFG->invalidate.xp.second.c_str());
1156           }
1157 
1158           size_t read_len = strlen(buf);
1159 
1160           // Replace tabs
1161           char *ht = buf;
1162           while((ht = strchr(ht, '\t')) != NULL) {
1163             int rposn = ht-buf;
1164             int rstart = rposn%tabsz+1;
1165             *ht = ' ';
1166             if(tabsz > rstart) {
1167               if((read_len + tabsz - rstart) >= (buf_len - 7)) {
1168                 buf_len += tabsz;
1169                 buf = (char*)throw_realloc(buf, buf_len);
1170               }
1171               strins(spaces+rstart, buf, rposn);
1172             }
1173           }
1174 
1175           // Copy the paragraph to the new line and retype it
1176           Line* _newline = __line = insertlinebelow(__line, buf);
1177           setlinetype(_newline);
1178 
1179           // If the paragraph is longer than one line
1180           uint _wrapmargin = (_newline->type & GLINE_QUOT) ? marginquotes : margintext;
1181           if(_newline->txt.length() >= _wrapmargin) {
1182 
1183             // Wrap it
1184             uint _tmpcol = 0;
1185             uint _tmprow = 0;
1186             _newline = wrapins(&_newline, &_tmpcol, &_tmprow, false);
1187           }
1188 
1189           __line = _newline;
1190         }
1191 
1192         while(__line->next)
1193           __line = __line->next;
1194         if(not __line->txt.empty() and (*(__line->txt.end()-1) != '\n')) {
1195           Undo->PushItem(EDIT_UNDO_INS_CHAR|BATCH_MODE, __line, __line->txt.length());
1196           __line->txt += '\n';
1197           // Wrap it
1198           uint _tmpcol = 0;
1199           uint _tmprow = 0;
1200           __line = wrapins(&__line, &_tmpcol, &_tmprow, false);
1201         }
1202         __line->next = saveline;
1203         if(saveline)
1204           saveline->prev = __line;
1205 
1206         throw_free(buf);
1207       }
1208 
1209       // Add import end text, if any
1210       if (*CFG->importend or *CFG->importbegin)
1211       {
1212         sprintf(_parabuf, "%s\n", *CFG->importend ? CFG->importend : CFG->importbegin);
1213         strischg(_parabuf, "@file", imp_filename);
1214         TokenXlat(MODE_NEW, _parabuf, EDIT_PARABUFLEN, true, msgptr, msgptr, CurrArea);
1215         _parabuf[strlen(_parabuf)-1] = '\n';
1216         _parabuf[margintext] = NUL;
1217         _parabuf[margintext-1] = '\n';
1218         __line = insertlinebelow(__line, _parabuf);
1219         setlinetype(__line);
1220       }
1221 
1222       throw_free(_parabuf);
1223 
1224       if (getclip)
1225         clipbrd.close();
1226       else
1227         fp.Fclose();
1228     }
1229     else {
1230       w_infof(LNG->CouldNotOpen, filenamebuf.c_str());
1231       waitkeyt(10000);
1232       w_info(NULL);
1233     }
1234 
1235     if(isPipe)
1236       unlink(tmpfile);
1237   }
1238 
1239   AA->SetXlatimport(__oldxlatimport);
1240 
1241   GFTRK(0);
1242 }
1243 
1244 
1245 //  ------------------------------------------------------------------
1246 
imptxt(char * __filename,bool imptxt)1247 void IEclass::imptxt(char* __filename, bool imptxt) {
1248 
1249   GFTRK("Editimptxt");
1250 
1251   msgptr->lin = findfirstline();
1252   editimport(currline, __filename, imptxt);
1253   refresh(currline, row);
1254   col = mincol;
1255 
1256   GFTRK(0);
1257 }
1258 
1259 
1260 //  ------------------------------------------------------------------
1261 
ImportText()1262 void IEclass::ImportText() {
1263 
1264   GFTRK("EditImportText");
1265 
1266   imptxt(NULL);
1267 
1268   GFTRK(0);
1269 }
1270 
1271 
1272 //  ------------------------------------------------------------------
1273 
ImportQuotebuf()1274 void IEclass::ImportQuotebuf() {
1275 
1276   GFTRK("EditImportQuotebuf");
1277 
1278   Path _quotebuf;
1279 
1280   GetCurrQuotebuf(_quotebuf);
1281   imptxt(_quotebuf, true);
1282 
1283   GFTRK(0);
1284 }
1285 
1286 
1287 //  ------------------------------------------------------------------
1288 
editexport(Line * __exportline,int __endat)1289 void IEclass::editexport(Line* __exportline, int __endat) {
1290 
1291   GFTRK("Editexport");
1292 
1293   update_statusline(LNG->ExportFile);
1294 
1295   if (edit_string(Edit__exportfilename, sizeof(Path), LNG->ExportWhatFile, H_ExportFile))
1296   {
1297     // Pointer to export filename
1298     char* _filenameptr = Edit__exportfilename;
1299 
1300     // Is append requested?
1301     if(*_filenameptr == '+')
1302       _filenameptr++;
1303 
1304     gfile _fp(_filenameptr, (*Edit__exportfilename == '+') ? "at" : "wt", CFG->sharemode);
1305     if (_fp.isopen())
1306     {
1307       update_statuslinef(LNG->ExportStatus, "ST_EXPORTSTATUS", Edit__exportfilename);
1308       _fp.Fputc('\n');
1309 
1310       while ((__endat ? __exportline != currline : 1) and __exportline)
1311       {
1312         _fp.Fwrite(__exportline->txt.c_str(), __exportline->txt.length());
1313         if (__exportline->txt.find('\n') == __exportline->txt.npos)
1314           _fp.Fputc('\n');
1315         __exportline = __exportline->next;
1316       }
1317     }
1318   }
1319 
1320   GFTRK(0);
1321 }
1322 
1323 
1324 //  ------------------------------------------------------------------
1325 
SpellCheck()1326 void IEclass::SpellCheck()
1327 {
1328   GFTRK("EditSpellCheck");
1329 
1330   char _buf[EDIT_BUFLEN];
1331   char _buf2[EDIT_BUFLEN];
1332 
1333   savefile(MODE_SAVE);
1334   strcpy(_buf, EDIT->SpellChecker());
1335   strcpy(_buf2, AddPath(CFG->goldpath, EDIT->File()));
1336   strchg(_buf2, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
1337   strischg(_buf, "@file", _buf2);
1338   gsprintf(PRINTF_DECLARE_BUFFER(_buf2), LNG->SpellChecker, _buf);
1339   ShellToDos(_buf, _buf2, LGREY_|_BLACK, YES);
1340   LoadFile();
1341 
1342   GFTRK(0);
1343 }
1344 
1345 
1346 //  ------------------------------------------------------------------
1347 
ExportText()1348 void IEclass::ExportText() {
1349 
1350   GFTRK("EditExportText");
1351 
1352   int endat = NO;
1353   // Line* exportline = findanchor();
1354 
1355   // if(exportline)
1356   //  endat = YES;
1357   // else
1358   Line* exportline = findfirstline();
1359 
1360   editexport(exportline, endat);
1361 
1362   GFTRK(0);
1363 }
1364 
1365 
1366 //  ------------------------------------------------------------------
1367 
DosShell()1368 void IEclass::DosShell() {
1369 
1370   GFTRK("EditDosShell");
1371 
1372   char * shell = getenv(GOLD_SHELL_ENV);
1373   if( shell && *shell )
1374     ShellToDos(shell, LNG->DOS_Shell, LGREY_|_BLACK, YES);
1375   cursoron();
1376   cursoroff();
1377 
1378   GFTRK(0);
1379 }
1380 
1381 
1382 //  ------------------------------------------------------------------
1383 
dispins()1384 void IEclass::dispins() {
1385 
1386   GFTRK("Editdispins");
1387 
1388   if(insert)
1389     HeaderView->window.prints(5, MAXCOL-6, C_HEADT, LNG->Ins);
1390   else {
1391     vchar _lbuf[6];
1392     for(int c = 0; c < 5; c++)
1393       _lbuf[c] = _box_table(W_BHEAD,1);
1394     _lbuf[5] = NUL;
1395     HeaderView->window.printvs(5, MAXCOL-6, C_HEADB|ACSET, _lbuf);
1396   }
1397 
1398   GFTRK(0);
1399 }
1400 
1401 
1402 //  ------------------------------------------------------------------
1403 
dispdl()1404 void IEclass::dispdl()
1405 {
1406   GFTRK("Editdispdl");
1407 
1408   if (drawlines)
1409   {
1410     const char *lng = (drawlines == 1) ? LNG->DrawSL : LNG->DrawDL;
1411     HeaderView->window.prints(5, MAXCOL-12, C_HEADT, lng);
1412   }
1413   else {
1414     vchar _lbuf[6];
1415     for(int c = 0; c < 5; c++)
1416       _lbuf[c] = _box_table(W_BHEAD,1);
1417     _lbuf[5] = NUL;
1418     HeaderView->window.printvs(5, MAXCOL-12, C_HEADB|ACSET, _lbuf);
1419   }
1420 
1421   GFTRK(0);
1422 }
1423 
1424 
1425 //  ------------------------------------------------------------------
1426 
ToggleInsert()1427 void IEclass::ToggleInsert() {
1428 
1429   GFTRK("EditToggleInsert");
1430 
1431   insert = not insert;
1432   dispins();
1433 
1434   GFTRK(0);
1435 }
1436 
1437 
1438 //  ------------------------------------------------------------------
1439 
ToggleDrawLines()1440 void IEclass::ToggleDrawLines()
1441 {
1442   GFTRK("EditToggleDrawLines");
1443 
1444   switch (drawlines)
1445   {
1446   case 0: drawlines = 1; break;
1447   case 1: drawlines = 2; break;
1448   case 2: drawlines = 0; break;
1449   }
1450 
1451   dispdl();
1452 
1453   GFTRK(0);
1454 }
1455 
1456 
1457 //  ------------------------------------------------------------------
1458 
ChrToLines(char chr,byte lines[4])1459 static void ChrToLines(char chr, byte lines[4])
1460 {
1461   lines[0] = lines[1] = lines[2] = lines[3] = 0;
1462 
1463   if      (chr == _box_table(0, 1))           //hs
1464     lines[0] = lines[1] = 1;
1465   else if (chr == _box_table(1, 1))           //hd
1466     lines[0] = lines[1] = 2;
1467   else if (chr == _box_table(0, 3))           //vs
1468     lines[2] = lines[3] = 1;
1469   else if (chr == _box_table(1, 3))           //vd
1470     lines[2] = lines[3] = 2;
1471 
1472   else if (chr == _box_table(0, 0))           //lsus
1473     lines[1] = lines[3] = 1;
1474   else if (chr == _box_table(1, 0))           //ldud
1475     lines[1] = lines[3] = 2;
1476   else if (chr == _box_table(0, 11))          //vsus
1477     lines[0] = lines[1] = lines[3] = 1;
1478   else if (chr == _box_table(1, 11))          //vdud
1479     lines[0] = lines[1] = lines[3] = 2;
1480   else if (chr == _box_table(0, 2))           //rsus
1481     lines[0] = lines[3] = 1;
1482   else if (chr == _box_table(1, 2))           //rdud
1483     lines[0] = lines[3] = 2;
1484 
1485   else if (chr == _box_table(0, 9))           //lshs
1486     lines[1] = lines[2] = lines[3] = 1;
1487   else if (chr == _box_table(1, 9))           //ldhd
1488     lines[1] = lines[2] = lines[3] = 2;
1489   else if (chr == _box_table(0, 8))           //vshs
1490     lines[0] = lines[1] = lines[2] = lines[3] = 1;
1491   else if (chr == _box_table(1, 8))           //vdhd
1492     lines[0] = lines[1] = lines[2] = lines[3] = 2;
1493   else if (chr == _box_table(0, 10))          //rshs
1494     lines[0] = lines[2] = lines[3] = 1;
1495   else if (chr == _box_table(1, 10))          //rdhd
1496     lines[0] = lines[2] = lines[3] = 2;
1497 
1498   else if (chr == _box_table(0, 5))           //lsds
1499     lines[1] = lines[2] = 1;
1500   else if (chr == _box_table(1, 5))           //lddd
1501     lines[1] = lines[2] = 2;
1502   else if (chr == _box_table(0, 12))          //vsds
1503     lines[0] = lines[1] = lines[2] = 1;
1504   else if (chr == _box_table(1, 12))          //vddd
1505     lines[0] = lines[1] = lines[2] = 2;
1506   else if (chr == _box_table(0, 7))           //rsds
1507     lines[0] = lines[2] = 1;
1508   else if (chr == _box_table(1, 7))           //rddd
1509     lines[0] = lines[2] = 2;
1510 
1511   else if (chr == _box_table(2, 0))           //ldus
1512   { lines[1] = 1; lines[3] = 2; }
1513   else if (chr == _box_table(3, 0))           //lsud
1514   { lines[1] = 2; lines[3] = 1; }
1515   else if (chr == _box_table(2, 11))          //vdus
1516   { lines[0] = lines[1] = 1; lines[3] = 2; }
1517   else if (chr == _box_table(3, 11))          //vsud
1518   { lines[0] = lines[1] = 2; lines[3] = 1; }
1519   else if (chr == _box_table(2, 2))           //rdus
1520   { lines[0] = 1; lines[3] = 2; }
1521   else if (chr == _box_table(3, 2))           //rsud
1522   { lines[0] = 2; lines[3] = 1; }
1523 
1524   else if (chr == _box_table(2, 9))           //ldhs
1525   { lines[1] = 1; lines[2] = lines[3] = 2; }
1526   else if (chr == _box_table(3, 9))           //lshd
1527   { lines[1] = 2; lines[2] = lines[3] = 1; }
1528   else if (chr == _box_table(2, 8))           //vdhs
1529   { lines[0] = lines[1] = 1; lines[2] = lines[3] = 2; }
1530   else if (chr == _box_table(3, 8))           //vshd
1531   { lines[0] = lines[1] = 2; lines[2] = lines[3] = 1; }
1532   else if (chr == _box_table(2, 10))          //rdhs
1533   { lines[0] = 1; lines[2] = lines[3] = 2; }
1534   else if (chr == _box_table(3, 10))          //rshd
1535   { lines[0] = 2; lines[2] = lines[3] = 1; }
1536 
1537   else if (chr == _box_table(2, 5))           //ldds
1538   { lines[1] = 1; lines[2] = 2; }
1539   else if (chr == _box_table(3, 5))           //lsdd
1540   { lines[1] = 2; lines[2] = 1; }
1541   else if (chr == _box_table(2, 12))          //vdds
1542   { lines[0] = lines[1] = 1; lines[2] = 2; }
1543   else if (chr == _box_table(3, 12))          //vsdd
1544   { lines[0] = lines[1] = 2; lines[2] = 1; }
1545   else if (chr == _box_table(2, 7))           //rdds
1546   { lines[0] = 1; lines[2] = 2; }
1547   else if (chr == _box_table(3, 7))           //rsdd
1548   { lines[0] = 2; lines[2] = 1; }
1549 }
1550 
1551 
1552 //  ------------------------------------------------------------------
1553 
LinesToChr(byte lines[4])1554 static char LinesToChr(byte lines[4])
1555 {
1556   if            (lines[0] == 0)
1557   { if          (lines[1] == 0)
1558     { if        (lines[2] == 0)
1559       { if      (lines[3] == 1) return _box_table(0, 3);    //vs
1560         if      (lines[3] == 2) return _box_table(1, 3);    //vd
1561       } else if (lines[2] == 1)
1562       { if      (lines[3] == 0) return _box_table(0, 3);    //vs
1563         if      (lines[3] == 1) return _box_table(0, 3);    //vs
1564       } else if (lines[2] == 2)
1565       { if      (lines[3] == 0) return _box_table(1, 3);    //vd
1566         if      (lines[3] == 2) return _box_table(1, 3);    //vd
1567       }
1568     } else if   (lines[1] == 1)
1569     { if        (lines[2] == 0)
1570       { if      (lines[3] == 0) return _box_table(0, 1);    //hs
1571         if      (lines[3] == 1) return _box_table(0, 0);    //lsus
1572         if      (lines[3] == 2) return _box_table(2, 0);    //ldus
1573       } else if (lines[2] == 1)
1574       { if      (lines[3] == 0) return _box_table(0, 5);    //lsds
1575         if      (lines[3] == 1) return _box_table(0, 9);    //lshs
1576       } else if (lines[2] == 2)
1577       { if      (lines[3] == 0) return _box_table(2, 5);    //ldds
1578         if      (lines[3] == 2) return _box_table(2, 9);    //ldhs
1579       }
1580     } else if   (lines[1] == 2)
1581     { if        (lines[2] == 0)
1582       { if      (lines[3] == 0) return _box_table(1, 1);    //hd
1583         if      (lines[3] == 1) return _box_table(3, 0);    //lsud
1584         if      (lines[3] == 2) return _box_table(1, 0);    //ldud
1585       } else if (lines[2] == 1)
1586       { if      (lines[3] == 0) return _box_table(3, 5);    //lsdd
1587         if      (lines[3] == 1) return _box_table(3, 9);    //lshd
1588       } else if (lines[2] == 2)
1589       { if      (lines[3] == 0) return _box_table(1, 5);    //lddd
1590         if      (lines[3] == 2) return _box_table(1, 9);    //ldhd
1591       }
1592     }
1593   } else if     (lines[0] == 1)
1594   { if          (lines[1] == 0)
1595     { if        (lines[2] == 0)
1596       { if      (lines[3] == 0) return _box_table(0, 1);    //hs
1597         if      (lines[3] == 1) return _box_table(0, 2);    //rsus
1598         if      (lines[3] == 2) return _box_table(2, 2);    //rdus
1599       } else if (lines[2] == 1)
1600       { if      (lines[3] == 0) return _box_table(0, 7);    //rsds
1601         if      (lines[3] == 1) return _box_table(0, 10);   //rshs
1602       } else if (lines[2] == 2)
1603       { if      (lines[3] == 0) return _box_table(2, 7);    //rdds
1604         if      (lines[3] == 2) return _box_table(2, 10);   //rdhs
1605       }
1606     } else if   (lines[1] == 1)
1607     { if        (lines[2] == 0)
1608       { if      (lines[3] == 0) return _box_table(0, 1);    //hs
1609         if      (lines[3] == 1) return _box_table(0, 11);   //vsus
1610         if      (lines[3] == 2) return _box_table(2, 11);   //vdus
1611       } else if (lines[2] == 1)
1612       { if      (lines[3] == 0) return _box_table(0, 12);   //vsds
1613         if      (lines[3] == 1) return _box_table(0, 8);    //vshs
1614       } else if (lines[2] == 2)
1615       { if      (lines[3] == 0) return _box_table(2, 12);   //vdds
1616         if      (lines[3] == 2) return _box_table(2, 8);    //vdhs
1617       }
1618     }
1619   } else if     (lines[0] == 2)
1620   { if          (lines[1] == 0)
1621     { if        (lines[2] == 0)
1622       { if      (lines[3] == 0) return _box_table(1, 1);    //hd
1623         if      (lines[3] == 1) return _box_table(3, 2);    //rsud
1624         if      (lines[3] == 2) return _box_table(1, 2);    //rdud
1625       } else if (lines[2] == 1)
1626       { if      (lines[3] == 0) return _box_table(3, 7);    //rsdd
1627         if      (lines[3] == 1) return _box_table(3, 10);   //rshd
1628       } else if (lines[2] == 2)
1629       { if      (lines[3] == 0) return _box_table(1, 7);    //rddd
1630         if      (lines[3] == 2) return _box_table(1, 10);   //rdhd
1631       }
1632     } else if   (lines[1] == 2)
1633     { if        (lines[2] == 0)
1634       { if      (lines[3] == 0) return _box_table(1, 1);   //hd
1635         if      (lines[3] == 1) return _box_table(3, 11);  //vsud
1636         if      (lines[3] == 2) return _box_table(1, 11);  //vdud
1637       } else if (lines[2] == 1)
1638       { if      (lines[3] == 0) return _box_table(3, 12);  //vsdd
1639         if      (lines[3] == 1) return _box_table(3, 8);   //vshd
1640       } else if (lines[2] == 2)
1641       { if      (lines[3] == 0) return _box_table(1, 12);  //vddd
1642         if      (lines[3] == 2) return _box_table(1, 8);   //vdhd
1643       }
1644     }
1645   }
1646 
1647   return 0x20;
1648 }
1649 
1650 
1651 //  ------------------------------------------------------------------
1652 
DrawLines(gkey key)1653 void IEclass::DrawLines(gkey key)
1654 {
1655   GFTRK("EditDrawLines");
1656 
1657   static byte lines[4];
1658   static int drawx;
1659   static int drawy;
1660 
1661   byte type1 = 1;
1662   byte type2 = 1;
1663 
1664   (drawlines == 1) ? type2 = 2 : type1 = 2;
1665 
1666   //-------------------------
1667   if (drawflag || chartyped)
1668   {
1669     ChrToLines(currline->txt[col], lines);
1670 
1671     switch (key)
1672     {
1673     case KK_EditBlockRight:
1674       drawx = -1; drawy = 0;
1675 
1676       if ((lines[0] == type1) || (!lines[0] && (lines[2] || lines[3])))
1677         drawx++;
1678       else if ((lines[0] == type2) || (lines[1] == type2))
1679       {
1680         drawx++; lines[0] = lines[1] = 0;
1681       }
1682 
1683       break;
1684 
1685     case KK_EditBlockLeft:
1686       drawx = +1; drawy = 0;
1687 
1688       if ((lines[1] == type1) || (!lines[1] && (lines[2] || lines[3])))
1689         drawx--;
1690       else if ((lines[0] == type2) || (lines[1] == type2))
1691       {
1692         drawx--; lines[0] = lines[1] = 0;
1693       }
1694 
1695       break;
1696 
1697     case KK_EditBlockDown:
1698       drawx = 0; drawy = -1;
1699 
1700       if ((lines[2] == type1) || (!lines[2] && (lines[0] || lines[1])))
1701         drawy++;
1702       else if ((lines[2] == type2) || (lines[3] == type2))
1703       {
1704         drawy++; lines[2] = lines[3] = 0;
1705       }
1706 
1707       break;
1708 
1709     case KK_EditBlockUp:
1710       drawx = 0; drawy = +1;
1711 
1712       if ((lines[3] == type1) || (!lines[3] && (lines[0] || lines[1])))
1713         drawy--;
1714       else if ((lines[2] == type2) || (lines[3] == type2))
1715       {
1716         drawy--; lines[2] = lines[3] = 0;
1717       }
1718 
1719       break;
1720     }
1721 
1722     drawflag = false;
1723   }
1724 
1725   //-------------------------
1726   bool gonext = true;
1727 
1728   switch (key)
1729   {
1730   case KK_EditBlockRight:
1731     if (col >= (maxcol-1)) { lines[1] = 0; gonext = false; }
1732 
1733     if (!drawx && gonext)
1734     {
1735       drawx = -1; lines[1] = type1;
1736       if (lines[0] == type2) lines[0] = 0;
1737     }
1738     else if (drawx == 1) drawx = -1;
1739     else if (drawx == -1)
1740     {
1741       gonext = false;
1742       drawx++; lines[0] = type1;
1743       if (lines[1] == type2) lines[1] = 0;
1744     }
1745 
1746     if (gonext && drawy)
1747     {
1748       if (drawy == -1)
1749       {
1750         drawy++; lines[2] = type1;
1751         lines[0] = lines[3] = 0;
1752       }
1753       else  //(drawy == 1)
1754       {
1755         drawy--; lines[3] = type1;
1756         lines[0] = lines[2] = 0;
1757       }
1758     }
1759     break;
1760 
1761   case KK_EditBlockLeft:
1762     if (col <= mincol) { lines[0] = 0; gonext = false; }
1763 
1764     if (!drawx && gonext)
1765     {
1766       drawx = 1; lines[0] = type1;
1767       if (lines[1] == type2) lines[1] = 0;
1768     }
1769     else if (drawx == -1) drawx = 1;
1770     else if (drawx == 1)
1771     {
1772       gonext = false;
1773       drawx--; lines[1] = type1;
1774       if (lines[0] == type2) lines[0] = 0;
1775     }
1776 
1777     if (gonext && drawy)
1778     {
1779       if (drawy == -1)
1780       {
1781         drawy++; lines[2] = type1;
1782         lines[1] = lines[3] = 0;
1783       }
1784       else  //(drawy == 1)
1785       {
1786         drawy--; lines[3] = type1;
1787         lines[1] = lines[2] = 0;
1788       }
1789     }
1790     break;
1791 
1792   case KK_EditBlockDown:
1793     if (!currline->next) { lines[3] = 0; gonext = false; }
1794 
1795     if (!drawy && gonext)
1796     {
1797       drawy = -1; lines[3] = type1;
1798       if (lines[2] == type2) lines[2] = 0;
1799     }
1800     else if (drawy == 1) drawy = -1;
1801     else if (drawy == -1)
1802     {
1803       gonext = false;
1804       drawy++; lines[2] = type1;
1805       if (lines[3] == type2) lines[3] = 0;
1806     }
1807 
1808     if (gonext && drawx)
1809     {
1810       if (drawx == -1)
1811       {
1812         drawx++; lines[0] = type1;
1813         lines[1] = lines[2] = 0;
1814       }
1815       else  //(drawx == 1)
1816       {
1817         drawx--; lines[1] = type1;
1818         lines[0] = lines[2] = 0;
1819       }
1820     }
1821     break;
1822 
1823   case KK_EditBlockUp:
1824     if (!currline->prev) { lines[2] = 0; gonext = false; }
1825 
1826     if (!drawy && gonext)
1827     {
1828       drawy = 1; lines[2] = type1;
1829       if (lines[3] == type2) lines[3] = 0;
1830     }
1831     else if (drawy == -1) drawy = 1;
1832     else if (drawy == 1)
1833     {
1834       gonext = false;
1835       drawy--; lines[3] = type1;
1836       if (lines[2] == type2) lines[2] = 0;
1837     }
1838 
1839     if (gonext && drawx)
1840     {
1841       if (drawx == -1)
1842       {
1843         drawx++; lines[0] = type1;
1844         lines[1] = lines[3] = 0;
1845       }
1846       else  //(drawx == 1)
1847       {
1848         drawx--; lines[1] = type1;
1849         lines[0] = lines[3] = 0;
1850       }
1851     }
1852     break;
1853   }
1854 
1855   //-------------------------
1856   char new_chr = LinesToChr(lines);
1857 
1858   if (new_chr != currline->txt[col])
1859   {
1860     if (col < (currline->txt.length()-1))
1861     {
1862       Undo->PushItem(EDIT_UNDO_OVR_CHAR);
1863       currline->txt[col] = new_chr;
1864     }
1865     else if (col < maxcol)
1866     {
1867       Undo->PushItem(EDIT_UNDO_INS_CHAR);
1868       currline->txt.insert(col, 1, new_chr);
1869     }
1870 
1871     setlinetype(currline);
1872     displine(currline, row);
1873   }
1874 
1875   //-------------------------
1876   if (gonext)
1877   {
1878     switch (key)
1879     {
1880     case KK_EditBlockRight: GoRight(); break;
1881     case KK_EditBlockLeft:  GoLeft();  break;
1882     default:
1883       (key == KK_EditBlockDown) ? GoDown() : GoUp();
1884       if (col < pcol)
1885       {
1886         size_t len = pcol - col;
1887         Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, currline, col, len);
1888         currline->txt.insert(col, len, ' ');
1889         GoEOL();
1890       }
1891       break;
1892     }
1893 
1894     gotorowcol(col, row);
1895     ChrToLines(currline->txt[col], lines);
1896 
1897     switch (key)
1898     {
1899     case KK_EditBlockRight:
1900       if ((drawx == -1) && (lines[0] == type1)) drawx++;
1901       break;
1902     case KK_EditBlockLeft:
1903       if ((drawx == +1) && (lines[1] == type1)) drawx--;
1904       break;
1905     case KK_EditBlockDown:
1906       if ((drawy == -1) && (lines[2] == type1)) drawy++;
1907       break;
1908     case KK_EditBlockUp:
1909       if ((drawy == +1) && (lines[3] == type1)) drawy--;
1910       break;
1911     }
1912   }
1913 
1914   GFTRK(0);
1915 }
1916 
1917 
1918 //  ------------------------------------------------------------------
1919 
Header()1920 void IEclass::Header() {
1921 
1922   GFTRK("EditHeader");
1923 
1924   windowclose();
1925   EditHeaderinfo(msgmode, *HeaderView);
1926   windowopen();
1927 
1928   GFTRK(0);
1929 }
1930 
1931 
1932 //  ------------------------------------------------------------------
1933 
Abort()1934 void IEclass::Abort() {
1935 
1936   GFTRK("EditAbort");
1937 
1938   cursoroff();
1939   GMenuDropmsg MenuDropmsg;
1940   if(MenuDropmsg.Run()) {
1941     done = MODE_QUIT;
1942   }
1943 
1944   GFTRK(0);
1945 }
1946 
1947 
1948 //  ------------------------------------------------------------------
1949 
AskExit()1950 void IEclass::AskExit() {
1951 
1952   GFTRK("EditAskExit");
1953 
1954   cursoroff();
1955   GMenuQuit MenuQuit;
1956   gkbd.quitall = make_bool(MenuQuit.Run());
1957   if(gkbd.quitall) {
1958     GMenuDropmsg MenuDropmsg;
1959     if(MenuDropmsg.Run())
1960       done = MODE_QUIT;
1961     else
1962       done = MODE_SAVE;
1963   }
1964 
1965   GFTRK(0);
1966 }
1967 
1968 
1969 //  ------------------------------------------------------------------
1970 
QuitNow()1971 void IEclass::QuitNow()
1972 {
1973   GFTRK("EditQuitNow");
1974 
1975   if (CFG->switches.get(timeoutsavemsg))
1976   {
1977     quitnow = NO;
1978     done = MODE_SAVE;
1979     msgptr->attr.lok1();
1980   }
1981   else
1982   {
1983     quitnow = YES;
1984     done = MODE_QUIT;
1985   }
1986 
1987   gkbd.quitall = YES;
1988 
1989   GFTRK(0);
1990 }
1991 
1992 
1993 //  ------------------------------------------------------------------
1994 
EditMsg(int __mode,uint * __position,GMsg * __msg)1995 int EditMsg(int __mode, uint* __position, GMsg* __msg) {
1996 
1997   IEclass Editor(0, MAXCOL-1, MINROW, MAXROW-2, 5);
1998   return Editor.Start(__mode, __position, __msg);
1999 }
2000 
2001 
2002 //  ------------------------------------------------------------------
2003