1 /*    o_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 "c_color.h"
11 #include "c_config.h"
12 #include "c_history.h"
13 #include "e_mark.h"
14 #include "e_tags.h"
15 #include "e_undo.h"
16 #include "ftever.h"
17 #include "i_modelview.h"
18 #include "i_view.h"
19 #include "o_cvsdiff.h"
20 #include "o_messages.h"
21 #include "o_svndiff.h"
22 #include "s_files.h"
23 #include "s_string.h"
24 #include "s_util.h"
25 
26 #include <ctype.h>
27 #include <time.h>
28 
29 SearchReplaceOptions LSearch;
30 int suspendLoads = 0;
31 
CreateViewPort(EView * V)32 EViewPort *EBuffer::CreateViewPort(EView *V) {
33     V->Port = new EEditPort(this, V);
34     AddView(V);
35 
36     if (Loaded == 0 && !suspendLoads) {
37         Load();
38 
39 #ifdef CONFIG_OBJ_MESSAGES
40         if (CompilerMsgs)
41             CompilerMsgs->FindFileErrors(this);
42 #endif
43 #ifdef CONFIG_OBJ_CVS
44         if (CvsDiffView) CvsDiffView->FindFileLines(this);
45 #endif
46 
47 #ifdef CONFIG_OBJ_SVN
48         if (SvnDiffView) SvnDiffView->FindFileLines(this);
49 #endif
50 
51         markIndex.retrieveForBuffer(this);
52 
53 #ifdef CONFIG_HISTORY
54         int r, c;
55 
56         if (RetrieveFPos(FileName, r, c) == 1)
57             SetNearPosR(c, r);
58         //printf("setting to c:%d r:%d f:%s", c, r, FileName);
59         V->Port->GetPos();
60         V->Port->ReCenter = 1;
61 
62 #ifdef CONFIG_BOOKMARKS
63         if (BFI (this,BFI_SaveBookmarks)==3) RetrieveBookmarks(this);
64 #endif
65 #endif
66     }
67     return V->Port;
68 }
69 
EEditPort(EBuffer * B,EView * V)70 EEditPort::EEditPort(EBuffer *B, EView *V) :
71     EViewPort(V),
72     Buffer(B),
73     OldTP(-1, -1),
74     Rows(0),
75     Cols(0)
76 {
77     GetPos();
78 
79     if (V && V->MView && V->MView->Win) {
80         V->MView->ConQuerySize(&Cols, &Rows);
81         Rows--;
82     }
83 }
84 
~EEditPort()85 EEditPort::~EEditPort() {
86     StorePos();
87 }
88 
Resize(int Width,int Height)89 void EEditPort::Resize(int Width, int Height) {
90     Cols = Width;
91     Rows = Height - 1;
92     RedrawAll();
93 }
94 
SetTop(int Col,int Line)95 int EEditPort::SetTop(int Col, int Line) {
96     int A, B;
97 
98     if (Line >= Buffer->VCount) Line = Buffer->VCount - 1;
99     if (Line < 0) Line = 0;
100 
101     A = Line;
102     B = Line + Rows;
103 
104     TP.Row = Line;
105     TP.Col = Col;
106 
107     if (A >= Buffer->VCount) A = Buffer->VCount - 1;
108     if (B >= Buffer->VCount) {
109         B = Buffer->VCount - 1;
110     }
111     Buffer->Draw(Buffer->VToR(A), -1);
112     return 1;
113 }
114 
StorePos()115 void EEditPort::StorePos() {
116     Buffer->CP = CP;
117     Buffer->TP = TP;
118 }
119 
GetPos()120 void EEditPort::GetPos() {
121     CP = Buffer->CP;
122     TP = Buffer->TP;
123 }
124 
ScrollY(int Delta)125 void EEditPort::ScrollY(int Delta) {
126     // optimization
127     // no need to scroll (clear) entire window which we are about to redraw
128     if (Delta >= Rows || -Delta >= Rows)
129         return ;
130 
131     if (Delta < 0) {
132         Delta = -Delta;
133         if (Delta > Rows) return;
134         View->MView->ConScroll(csDown, 0, 0, Cols, Rows, hcPlain_Background, Delta);
135     } else {
136         if (Delta > Rows) return;
137         View->MView->ConScroll(csUp, 0, 0, Cols, Rows, hcPlain_Background, Delta);
138     }
139 }
140 
DrawLine(int L,TDrawBuffer B)141 void EEditPort::DrawLine(int L, TDrawBuffer B) {
142     if (L < TP.Row) return;
143     if (L >= TP.Row + Rows) return;
144     if (View->MView->Win->GetViewContext() == View->MView)
145         View->MView->ConPutBox(0, L - TP.Row, Cols, 1, B);
146     //    printf("%d %d (%d %d %d %d)\n", 0, L - TP.Row, view->sX, view->sY, view->sW, view->sH);
147 }
148 
RedrawAll()149 void EEditPort::RedrawAll() {
150     Buffer->Draw(TP.Row, -1);
151     ///    Redraw(0, 0, Cols, Rows);
152 }
153 
GetContext()154 int EBuffer::GetContext() {
155     return CONTEXT_FILE;
156 }
157 
HandleEvent(TEvent & Event)158 void EEditPort::HandleEvent(TEvent &Event) {
159     EViewPort::HandleEvent(Event);
160     switch (Event.What) {
161     case evKeyDown:
162         {
163             char Ch;
164             if (GetCharFromEvent(Event, &Ch)) {
165                 if (Buffer->BeginMacro() == 0)
166                     return ;
167                 Buffer->TypeChar(Ch);
168                 Event.What = evNone;
169             }
170         }
171         break;
172     case evCommand:
173         switch (Event.Msg.Command) {
174         case cmVScrollUp:
175             Buffer->ScrollDown(Event.Msg.Param1);
176             Event.What = evNone;
177             break;
178         case cmVScrollDown:
179             Buffer->ScrollUp(Event.Msg.Param1);
180             Event.What = evNone;
181             break;
182         case cmVScrollPgUp:
183             Buffer->ScrollDown(Rows);
184             Event.What = evNone;
185             break;
186         case cmVScrollPgDn:
187             Buffer->ScrollUp(Rows);
188             Event.What = evNone;
189             break;
190         case cmVScrollMove:
191             {
192                 int ypos;
193 
194 //                fprintf(stderr, "Pos = %d\n\x7", Event.Msg.Param1);
195                 ypos = Buffer->CP.Row - TP.Row;
196                 Buffer->SetNearPos(Buffer->CP.Col, Event.Msg.Param1 + ypos);
197                 SetTop(TP.Col, Event.Msg.Param1);
198                 RedrawAll();
199             }
200             Event.What = evNone;
201             break;
202         case cmHScrollLeft:
203             Buffer->ScrollRight(Event.Msg.Param1);
204             Event.What = evNone;
205             break;
206         case cmHScrollRight:
207             Buffer->ScrollLeft(Event.Msg.Param1);
208             Event.What = evNone;
209             break;
210         case cmHScrollPgLt:
211             Buffer->ScrollRight(Cols);
212             Event.What = evNone;
213             break;
214         case cmHScrollPgRt:
215             Buffer->ScrollLeft(Cols);
216             Event.What = evNone;
217             break;
218         case cmHScrollMove:
219             {
220                 int xpos;
221 
222                 xpos = Buffer->CP.Col - TP.Col;
223                 Buffer->SetNearPos(Event.Msg.Param1 + xpos, Buffer->CP.Row);
224                 SetTop(Event.Msg.Param1, TP.Row);
225                 RedrawAll();
226             }
227             Event.What = evNone;
228             break;
229         }
230         break;
231 #ifdef CONFIG_MOUSE
232     case evMouseDown:
233     case evMouseMove:
234     case evMouseAuto:
235     case evMouseUp:
236         HandleMouse(Event);
237         break;
238 #endif
239     }
240 }
241 #ifdef CONFIG_MOUSE
HandleMouse(TEvent & Event)242 void EEditPort::HandleMouse(TEvent &Event) {
243     int x, y, xx, yy, W, H;
244 
245     View->MView->ConQuerySize(&W, &H);
246 
247     x = Event.Mouse.X;
248     y = Event.Mouse.Y;
249 
250     if (Event.What != evMouseDown || y < H - 1) {
251         xx = x + TP.Col;
252         yy = y + TP.Row;
253         if (yy >= Buffer->VCount) yy = Buffer->VCount - 1;
254         if (yy < 0) yy = 0;
255         if (xx < 0) xx = 0;
256 
257         switch (Event.What) {
258         case evMouseDown:
259             if (Event.Mouse.Y == H - 1)
260                 break;
261             if (View->MView->Win->CaptureMouse(1))
262                 View->MView->MouseCaptured = 1;
263             else
264                 break;
265 
266             View->MView->MouseMoved = 0;
267 
268             if (Event.Mouse.Buttons == 1) {
269                 // left mouse button down
270                 Buffer->SetNearPos(xx, yy);
271                 switch (Event.Mouse.Count % 5) {
272                 case 1:
273                     break;
274                 case 2:
275                     Buffer->BlockSelectWord();
276                     break;
277                 case 3:
278                     Buffer->BlockSelectLine();
279                     break;
280                 case 4:
281                     Buffer->BlockSelectPara();
282                     break;
283                 }
284                 //            Window->Buffer->Redraw();
285                 if (SystemClipboard) {
286                     // note: copy to second clipboard
287                     Buffer->NextCommand();
288                     Buffer->BlockCopy(0, 1);
289                 }
290                 Event.What = evNone;
291             } else if (Event.Mouse.Buttons == 2) {
292                 // right mouse button down
293                 Buffer->SetNearPos(xx, yy);
294             }
295             break;
296         case evMouseAuto:
297         case evMouseMove:
298             if (View->MView->MouseCaptured) {
299                 if (Event.Mouse.Buttons == 1) {
300                     // left mouse button move
301                     if (!View->MView->MouseMoved) {
302                         if (Event.Mouse.KeyMask == kfCtrl) Buffer->BlockMarkColumn();
303                         else if (Event.Mouse.KeyMask == kfAlt) Buffer->BlockMarkLine();
304                         else Buffer->BlockMarkStream();
305                         Buffer->BlockUnmark();
306                         if (Event.What == evMouseMove)
307                             View->MView->MouseMoved = 1;
308                     }
309                     Buffer->BlockExtendBegin();
310                     Buffer->SetNearPos(xx, yy);
311                     Buffer->BlockExtendEnd();
312                 } else if (Event.Mouse.Buttons == 2) {
313                     // right mouse button move
314                     if (Event.Mouse.KeyMask == kfAlt) {
315                     } else {
316                         Buffer->SetNearPos(xx, yy);
317                     }
318                 }
319 
320                 Event.What = evNone;
321             }
322             break;
323 /*        case evMouseAuto:
324             if (View->MView->MouseCaptured) {
325                 Event.What = evNone;
326             }
327             break;*/
328         case evMouseUp:
329             if (View->MView->MouseCaptured)
330                 View->MView->Win->CaptureMouse(0);
331             else
332                 break;
333             View->MView->MouseCaptured = 0;
334             if (Event.Mouse.Buttons == 1) {
335                 // left mouse button up
336                 if (View->MView->MouseMoved)
337                     if (SystemClipboard) {
338                         // note: copy to second clipboard
339                         Buffer->NextCommand();
340                         Buffer->BlockCopy(0, 1);
341                     }
342             }
343             if (Event.Mouse.Buttons == 2) {
344                 // right mouse button up
345                 if (!View->MView->MouseMoved) {
346                     EEventMap *Map = View->MView->Win->GetEventMap();
347                     const char *MName = 0;
348 
349                     if (Map)
350                         MName = Map->GetMenu(EM_LocalMenu);
351                     if (MName == 0)
352                         MName = "Local";
353                     View->MView->Win->Parent->PopupMenu(MName);
354                 }
355             }
356             if (Event.Mouse.Buttons == 4) {
357                 // middle mouse button up
358                 if (SystemClipboard) {
359                     // note: copy to second clipboard
360                     Buffer->NextCommand();
361                     if (Event.Mouse.KeyMask == 0)
362                         Buffer->BlockPasteStream(1);
363                     else if (Event.Mouse.KeyMask == kfCtrl)
364                         Buffer->BlockPasteColumn(1);
365                     else if (Event.Mouse.KeyMask == kfAlt)
366                         Buffer->BlockPasteLine(1);
367                 }
368             }
369             Event.What = evNone;
370             break;
371         }
372     }
373 }
374 #endif
375 
UpdateView()376 void EEditPort::UpdateView() {
377     Buffer->Redraw();
378 }
379 
RepaintView()380 void EEditPort::RepaintView() {
381     RedrawAll();
382 }
383 
UpdateStatus()384 void EEditPort::UpdateStatus() {
385 }
386 
RepaintStatus()387 void EEditPort::RepaintStatus() {
388     //Buffer->Redraw();
389 }
390 
GetEventMap()391 EEventMap *EBuffer::GetEventMap() {
392     return FindActiveMap(Mode);
393 }
394 
BeginMacro()395 int EBuffer::BeginMacro() {
396     return NextCommand();
397 }
398 
399 // *INDENT-OFF*
ExecCommand(ExCommands Command,ExState & State)400 int EBuffer::ExecCommand(ExCommands Command, ExState &State) {
401     switch (Command) {
402     case ExMoveUp:                return MoveUp();
403     case ExMoveDown:              return MoveDown();
404     case ExMoveLeft:              return MoveLeft();
405     case ExMoveRight:             return MoveRight();
406     case ExMovePrev:              return MovePrev();
407     case ExMoveNext:              return MoveNext();
408     case ExMoveWordLeft:          return MoveWordLeft();
409     case ExMoveWordRight:         return MoveWordRight();
410     case ExMoveWordPrev:          return MoveWordPrev();
411     case ExMoveWordNext:          return MoveWordNext();
412     case ExMoveWordEndLeft:       return MoveWordEndLeft();
413     case ExMoveWordEndRight:      return MoveWordEndRight();
414     case ExMoveWordEndPrev:       return MoveWordEndPrev();
415     case ExMoveWordEndNext:       return MoveWordEndNext();
416     case ExMoveWordOrCapLeft:     return MoveWordOrCapLeft();
417     case ExMoveWordOrCapRight:    return MoveWordOrCapRight();
418     case ExMoveWordOrCapPrev:     return MoveWordOrCapPrev();
419     case ExMoveWordOrCapNext:     return MoveWordOrCapNext();
420     case ExMoveWordOrCapEndLeft:  return MoveWordOrCapEndLeft();
421     case ExMoveWordOrCapEndRight: return MoveWordOrCapEndRight();
422     case ExMoveWordOrCapEndPrev:  return MoveWordOrCapEndPrev();
423     case ExMoveWordOrCapEndNext:  return MoveWordOrCapEndNext();
424     case ExMoveLineStart:         return MoveLineStart();
425     case ExMoveLineEnd:           return MoveLineEnd();
426     case ExMovePageStart:         return MovePageStart();
427     case ExMovePageEnd:           return MovePageEnd();
428     case ExMovePageUp:            return MovePageUp();
429     case ExMovePageDown:          return MovePageDown();
430     case ExMovePageLeft:          return MovePageLeft();
431     case ExMovePageRight:         return MovePageEnd();
432     case ExMoveFileStart:         return MoveFileStart();
433     case ExMoveFileEnd:           return MoveFileEnd();
434     case ExMoveBlockStart:        return MoveBlockStart();
435     case ExMoveBlockEnd:          return MoveBlockEnd();
436     case ExMoveFirstNonWhite:     return MoveFirstNonWhite();
437     case ExMoveLastNonWhite:      return MoveLastNonWhite();
438     case ExMovePrevEqualIndent:   return MovePrevEqualIndent();
439     case ExMoveNextEqualIndent:   return MoveNextEqualIndent();
440     case ExMovePrevTab:           return MovePrevTab();
441     case ExMoveNextTab:           return MoveNextTab();
442     case ExMoveTabStart:          return MoveTabStart();
443     case ExMoveTabEnd:            return MoveTabEnd();
444     case ExMoveLineTop:           return MoveLineTop();
445     case ExMoveLineCenter:        return MoveLineCenter();
446     case ExMoveLineBottom:        return MoveLineBottom();
447     case ExMoveBeginOrNonWhite:   return MoveBeginOrNonWhite();
448     case ExMoveBeginLinePageFile: return MoveBeginLinePageFile();
449     case ExMoveEndLinePageFile:   return MoveEndLinePageFile();
450     case ExScrollLeft:            return ScrollLeft(State);
451     case ExScrollRight:           return ScrollRight(State);
452     case ExScrollDown:            return ScrollDown(State);
453     case ExScrollUp:              return ScrollUp(State);
454     case ExKillLine:              return KillLine();
455     case ExKillChar:              return KillChar();
456     case ExKillCharPrev:          return KillCharPrev();
457     case ExKillWord:              return KillWord();
458     case ExKillWordPrev:          return KillWordPrev();
459     case ExKillWordOrCap:         return KillWordOrCap();
460     case ExKillWordOrCapPrev:     return KillWordOrCapPrev();
461     case ExKillToLineStart:       return KillToLineStart();
462     case ExKillToLineEnd:         return KillToLineEnd();
463     case ExKillBlock:             return KillBlock();
464     case ExBackSpace:             return BackSpace();
465     case ExDelete:                return Delete();
466     case ExCharCaseUp:            return CharCaseUp();
467     case ExCharCaseDown:          return CharCaseDown();
468     case ExCharCaseToggle:        return CharCaseToggle();
469     case ExLineCaseUp:            return LineCaseUp();
470     case ExLineCaseDown:          return LineCaseDown();
471     case ExLineCaseToggle:        return LineCaseToggle();
472     case ExLineInsert:            return LineInsert();
473     case ExLineAdd:               return LineAdd();
474     case ExLineSplit:             return LineSplit();
475     case ExLineJoin:              return LineJoin();
476     case ExLineNew:               return LineNew();
477     case ExLineIndent:            return LineIndent();
478     case ExLineTrim:              return LineTrim();
479     case ExLineCenter:            return LineCenter();
480     case ExInsertSpacesToTab:
481         {
482             int no;
483 
484             if(State.GetIntParam(View, &no) == 0)
485                 no = 0;
486             return InsertSpacesToTab(no);
487         }
488     case ExInsertTab:             return InsertTab();
489     case ExInsertSpace:           return InsertSpace();
490     case ExWrapPara:
491 #ifdef CONFIG_WORDWRAP
492         return WrapPara();
493 #else
494         return 0;
495 #endif
496     case ExInsPrevLineChar:       return InsPrevLineChar();
497     case ExInsPrevLineToEol:      return InsPrevLineToEol();
498     case ExLineDuplicate:         return LineDuplicate();
499     case ExBlockBegin:            return BlockBegin();
500     case ExBlockEnd:              return BlockEnd();
501     case ExBlockUnmark:           return BlockUnmark();
502     case ExBlockCut:              return BlockCut(0);
503     case ExBlockCopy:             return BlockCopy(0);
504     case ExBlockCutAppend:        return BlockCut(1);
505     case ExBlockCopyAppend:       return BlockCopy(1);
506     case ExClipClear:             return ClipClear();
507     case ExBlockPaste:            return BlockPaste();
508     case ExBlockKill:             return BlockKill();
509     case ExBlockIndent:
510         {
511             int saved_persistence, ret_code;
512 
513             saved_persistence = BFI(this, BFI_PersistentBlocks);
514             BFI_SET(this, BFI_PersistentBlocks, 1);
515             ret_code = BlockIndent();
516             BFI_SET(this, BFI_PersistentBlocks, saved_persistence);
517             return ret_code;
518         }
519     case ExBlockUnindent:
520         {
521             int saved_persistence, ret_code;
522 
523             saved_persistence = BFI(this, BFI_PersistentBlocks);
524             BFI_SET(this, BFI_PersistentBlocks, 1);
525             ret_code = BlockUnindent();
526             BFI_SET(this, BFI_PersistentBlocks, saved_persistence);
527             return ret_code;
528         }
529     case ExBlockClear:            return BlockClear();
530     case ExBlockMarkStream:       return BlockMarkStream();
531     case ExBlockMarkLine:         return BlockMarkLine();
532     case ExBlockMarkColumn:       return BlockMarkColumn();
533     case ExBlockCaseUp:           return BlockCaseUp();
534     case ExBlockCaseDown:         return BlockCaseDown();
535     case ExBlockCaseToggle:       return BlockCaseToggle();
536     case ExBlockExtendBegin:      return BlockExtendBegin();
537     case ExBlockExtendEnd:        return BlockExtendEnd();
538     case ExBlockReIndent:         return BlockReIndent();
539     case ExBlockSelectWord:       return BlockSelectWord();
540     case ExBlockSelectLine:       return BlockSelectLine();
541     case ExBlockSelectPara:       return BlockSelectPara();
542     case ExBlockUnTab:            return BlockUnTab();
543     case ExBlockEnTab:            return BlockEnTab();
544 #ifdef CONFIG_UNDOREDO
545     case ExUndo:                  return Undo();
546     case ExRedo:                  return Redo();
547 #else
548     case ExUndo:                  return 0;
549     case ExRedo:                  return 0;
550 #endif
551     case ExMatchBracket:          return MatchBracket();
552     case ExMovePrevPos:           return MovePrevPos();
553     case ExMoveSavedPosCol:       return MoveSavedPosCol();
554     case ExMoveSavedPosRow:       return MoveSavedPosRow();
555     case ExMoveSavedPos:          return MoveSavedPos();
556     case ExSavePos:               return SavePos();
557     case ExCompleteWord:          return CompleteWord();
558     case ExBlockPasteStream:      return BlockPasteStream();
559     case ExBlockPasteLine:        return BlockPasteLine();
560     case ExBlockPasteColumn:      return BlockPasteColumn();
561     case ExBlockPasteOver:        return BlockPasteOver();
562     case ExShowPosition:          return ShowPosition();
563     case ExFoldCreate:            return FoldCreate(VToR(CP.Row));
564     case ExFoldDestroy:           return FoldDestroy(VToR(CP.Row));
565     case ExFoldDestroyAll:        return FoldDestroyAll();
566     case ExFoldPromote:           return FoldPromote(VToR(CP.Row));
567     case ExFoldDemote:            return FoldDemote(VToR(CP.Row));
568     case ExFoldOpen:              return FoldOpen(VToR(CP.Row));
569     case ExFoldOpenNested:        return FoldOpenNested();
570     case ExFoldClose:             return FoldClose(VToR(CP.Row));
571     case ExFoldOpenAll:           return FoldOpenAll();
572     case ExFoldCloseAll:          return FoldCloseAll();
573     case ExFoldToggleOpenClose:   return FoldToggleOpenClose();
574     case ExFoldCreateAtRoutines:  return FoldCreateAtRoutines();
575     case ExMoveFoldTop:           return MoveFoldTop();
576     case ExMoveFoldPrev:          return MoveFoldPrev();
577     case ExMoveFoldNext:          return MoveFoldNext();
578     case ExFileSave:              return Save();
579     case ExFilePrint:             return FilePrint();
580     case ExBlockPrint:            return BlockPrint();
581     case ExBlockTrim:             return BlockTrim();
582     case ExFileTrim:              return FileTrim();
583     case ExHilitWord:
584 #ifdef CONFIG_WORD_HILIT
585         return HilitWord();
586 #else
587         return 0;
588 #endif
589     case ExSearchWordPrev:        return SearchWord(SEARCH_BACK | SEARCH_NEXT);
590     case ExSearchWordNext:        return SearchWord(SEARCH_NEXT);
591     case ExHilitMatchBracket:     return HilitMatchBracket();
592     case ExToggleAutoIndent:      return ToggleAutoIndent();
593     case ExToggleInsert:          return ToggleInsert();
594     case ExToggleExpandTabs:      return ToggleExpandTabs();
595     case ExToggleShowTabs:        return ToggleShowTabs();
596     case ExToggleUndo:            return ToggleUndo();
597     case ExToggleReadOnly:        return ToggleReadOnly();
598     case ExToggleKeepBackups:     return ToggleKeepBackups();
599     case ExToggleMatchCase:       return ToggleMatchCase();
600     case ExToggleBackSpKillTab:   return ToggleBackSpKillTab();
601     case ExToggleDeleteKillTab:   return ToggleDeleteKillTab();
602     case ExToggleSpaceTabs:       return ToggleSpaceTabs();
603     case ExToggleIndentWithTabs:  return ToggleIndentWithTabs();
604     case ExToggleBackSpUnindents: return ToggleBackSpUnindents();
605     case ExToggleWordWrap:        return ToggleWordWrap();
606     case ExToggleTrim:            return ToggleTrim();
607     case ExToggleShowMarkers:     return ToggleShowMarkers();
608     case ExToggleHilitTags:       return ToggleHilitTags();
609     case ExToggleShowBookmarks:   return ToggleShowBookmarks();
610     case ExToggleMakeBackups:     return ToggleMakeBackups();
611     case ExSetLeftMargin:         return SetLeftMargin();
612     case ExSetRightMargin:        return SetRightMargin();
613     case ExSetIndentWithTabs:     return SetIndentWithTabs(State);
614 
615         // stuff with UI
616     case ExMoveToLine:          return MoveToLine(State);
617     case ExMoveToColumn:        return MoveToColumn(State);
618     case ExFoldCreateByRegexp:  return FoldCreateByRegexp(State);
619 #ifdef CONFIG_BOOKMARKS
620     case ExPlaceBookmark:       return PlaceBookmark(State);
621     case ExRemoveBookmark:      return RemoveBookmark(State);
622     case ExGotoBookmark:        return GotoBookmark(State);
623 #else
624     case ExPlaceBookmark:       return 0;
625     case ExRemoveBookmark:      return 0;
626     case ExGotoBookmark:        return 0;
627 #endif
628     case ExPlaceGlobalBookmark: return PlaceGlobalBookmark(State);
629     case ExPushGlobalBookmark:  return PushGlobalBookmark();
630     case ExInsertString:        return InsertString(State);
631     case ExSelfInsert:          return SelfInsert(State);
632     case ExFileReload:          return FileReload(State);
633     case ExFileSaveAs:          return FileSaveAs(State);
634     case ExFileWriteTo:         return FileWriteTo(State);
635     case ExBlockRead:           return BlockRead(State);
636     case ExBlockReadStream:     return BlockReadStream(State);
637     case ExBlockReadLine:       return BlockReadLine(State);
638     case ExBlockReadColumn:     return BlockReadColumn(State);
639     case ExBlockWrite:          return BlockWrite(State);
640     case ExBlockSort:           return BlockSort(0);
641     case ExBlockSortReverse:    return BlockSort(1);
642     case ExFind:                return Find(State);
643     case ExFindReplace:         return FindReplace(State);
644     case ExFindRepeat:          return FindRepeat(State);
645     case ExFindRepeatOnce:      return FindRepeatOnce(State);
646     case ExFindRepeatReverse:   return FindRepeatReverse(State);
647     case ExSearch:              return Search(State);
648     case ExSearchB:             return SearchB(State);
649     case ExSearchRx:            return SearchRx(State);
650     case ExSearchAgain:         return SearchAgain(State);
651     case ExSearchAgainB:        return SearchAgainB(State);
652     case ExSearchReplace:       return SearchReplace(State);
653     case ExSearchReplaceB:      return SearchReplaceB(State);
654     case ExSearchReplaceRx:     return SearchReplaceRx(State);
655     case ExInsertChar:          return InsertChar(State);
656     case ExTypeChar:            return TypeChar(State);
657     case ExChangeMode:          return ChangeMode(State);
658     //case ExChangeKeys:          return ChangeKeys(State);
659     case ExChangeFlags:         return ChangeFlags(State);
660     case ExChangeTabSize:       return ChangeTabSize(State);
661     case ExChangeLeftMargin:    return ChangeLeftMargin(State);
662     case ExChangeRightMargin:   return ChangeRightMargin(State);
663     case ExASCIITable:
664 #ifdef CONFIG_I_ASCII
665         return ASCIITable(State);
666 #else
667         return 0;
668 #endif
669     case ExCharTrans:           return CharTrans(State);
670     case ExLineTrans:           return LineTrans(State);
671     case ExBlockTrans:          return BlockTrans(State);
672 
673 #ifdef CONFIG_TAGS
674     case ExTagFind:             return FindTag(State);
675     case ExTagFindWord:         return FindTagWord(State);
676 #endif
677 
678     case ExSetCIndentStyle:     return SetCIndentStyle(State);
679 
680     case ExBlockMarkFunction:   return BlockMarkFunction();
681     case ExIndentFunction:      return IndentFunction();
682     case ExMoveFunctionPrev:    return MoveFunctionPrev();
683     case ExMoveFunctionNext:    return MoveFunctionNext();
684     case ExInsertDate:          return InsertDate(State);
685     case ExInsertUid:           return InsertUid();
686     case ExShowHelpWord:        return ShowHelpWord(State);
687     default:
688         ;
689     }
690     return EModel::ExecCommand(Command, State);
691 }
692 // *INDENT-ON*
693 
HandleEvent(TEvent & Event)694 void EBuffer::HandleEvent(TEvent &Event) {
695     EModel::HandleEvent(Event);
696 }
697 
MoveToLine(ExState & State)698 int EBuffer::MoveToLine(ExState &State) {
699     int No = 0;
700 
701     if (State.GetIntParam(View, &No) == 0) {
702         char Num[10];
703 
704         sprintf(Num, "%d", VToR(CP.Row) + 1);
705         if (View->MView->Win->GetStr("Goto Line", sizeof(Num), Num, HIST_POSITION) == 0)
706             return 0;
707         No = atol(Num);
708     }
709     return SetNearPosR(CP.Col, No - 1);
710 }
711 
MoveToColumn(ExState & State)712 int EBuffer::MoveToColumn(ExState &State) {
713     int No = 0;
714 
715     if (State.GetIntParam(View, &No) == 0) {
716         char Num[10];
717 
718         sprintf(Num, "%d", CP.Col + 1);
719         if (View->MView->Win->GetStr("Goto Column", 8, Num, HIST_POSITION) == 0) return 0;
720         No = atol(Num);
721     }
722     return SetNearPos(No - 1, CP.Row);
723 }
724 
FoldCreateByRegexp(ExState & State)725 int EBuffer::FoldCreateByRegexp(ExState &State) {
726     char strbuf[1024] = "";
727 
728     if (State.GetStrParam(View, strbuf, sizeof(strbuf)) == 0) {
729         if (View->MView->Win->GetStr("Create Fold Regexp", sizeof(strbuf), strbuf, HIST_REGEXP) == 0) return 0;
730     }
731     return FoldCreateByRegexp(strbuf);
732 }
733 
734 #ifdef CONFIG_BOOKMARKS
PlaceUserBookmark(const char * n,EPoint P)735 int EBuffer::PlaceUserBookmark(const char *n,EPoint P) {
736     char name[256+4] = "_BMK";
737     int result;
738     EPoint prev;
739 
740     strcpy (name+4,n);
741     if (GetBookmark (name,prev)==0) {
742         prev.Row=-1;prev.Col=-1;
743     }
744     result=PlaceBookmark(name, P);
745     if (result) {
746         if (BFI (this,BFI_ShowBookmarks)) {
747             FullRedraw ();
748         }
749         if (BFI (this,BFI_SaveBookmarks)==1||BFI (this,BFI_SaveBookmarks)==2) {
750             if (!Modify ()) return result;   // Never try to save to read-only
751 #ifdef CONFIG_UNDOREDO
752             if (BFI(this, BFI_Undo)) {
753                 if (PushULong(prev.Row) == 0) return 0;
754                 if (PushULong(prev.Col) == 0) return 0;
755                 if (PushUData(n, strlen(n) + 1) == 0) return 0;
756                 if (PushULong(strlen (n)+1) == 0) return 0;
757                 if (PushUChar(ucPlaceUserBookmark) == 0) return 0;
758             }
759 #endif
760         }
761     }
762     return result;
763 }
764 
RemoveUserBookmark(const char * n)765 int EBuffer::RemoveUserBookmark(const char *n) {
766     char name[256+4] = "_BMK";
767     int result;
768     EPoint p;
769 
770     strcpy (name+4,n);
771     GetBookmark (name,p);       // p is valid only if remove is successful
772     result=RemoveBookmark(name);
773     if (result) {
774         if (BFI (this,BFI_ShowBookmarks)) {
775             FullRedraw ();
776         }
777         if (BFI (this,BFI_SaveBookmarks)==1||BFI (this,BFI_SaveBookmarks)==2) {
778             if (!Modify ()) return result;   // Never try to save to read-only
779 #ifdef CONFIG_UNDOREDO
780             if (PushULong(p.Row) == 0) return 0;
781             if (PushULong(p.Col) == 0) return 0;
782             if (PushUData((void *)n,strlen (n)+1) == 0) return 0;
783             if (PushULong(strlen (n)+1) == 0) return 0;
784             if (PushUChar(ucRemoveUserBookmark) == 0) return 0;
785 #endif
786         }
787     }
788     return result;
789 }
790 
GotoUserBookmark(const char * n)791 int EBuffer::GotoUserBookmark(const char *n) {
792     char name[256+4] = "_BMK";
793 
794     strcpy (name+4,n);
795     return GotoBookmark(name);
796 }
797 
GetUserBookmarkForLine(int searchFrom,int searchForLine,const EBookmark * & eb)798 int EBuffer::GetUserBookmarkForLine(int searchFrom, int searchForLine, const EBookmark* &eb) {
799     int i = searchFrom;
800 
801     while ((i = GetBookmarkForLine(i, searchForLine, eb) != -1))
802         if (strncmp(eb->GetName(), "_BMK", 4) == 0)
803             return i;
804 
805     return -1;
806 }
807 
PlaceBookmark(ExState & State)808 int EBuffer::PlaceBookmark(ExState &State) {
809     char name[256] = "";
810     EPoint P = CP;
811 
812     P.Row = VToR(P.Row);
813 
814     if (State.GetStrParam(View, name, sizeof(name)) == 0)
815         if (View->MView->Win->GetStr("Place Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0;
816     return PlaceUserBookmark(name, P);
817 }
818 
RemoveBookmark(ExState & State)819 int EBuffer::RemoveBookmark(ExState &State) {
820     char name[256] = "";
821 
822     if (State.GetStrParam(View, name, sizeof(name)) == 0)
823         if (View->MView->Win->GetStr("Remove Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0;
824     return RemoveUserBookmark(name);
825 }
826 
GotoBookmark(ExState & State)827 int EBuffer::GotoBookmark(ExState &State) {
828     char name[256] = "";
829 
830     if (State.GetStrParam(View, name, sizeof(name)) == 0)
831         if (View->MView->Win->GetStr("Goto Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0;
832     return GotoUserBookmark(name);
833 }
834 #endif
835 
PlaceGlobalBookmark(ExState & State)836 int EBuffer::PlaceGlobalBookmark(ExState &State) {
837     char name[256] = "";
838     EPoint P = CP;
839 
840     P.Row = VToR(P.Row);
841 
842     if (State.GetStrParam(View, name, sizeof(name)) == 0)
843         if (View->MView->Win->GetStr("Place Global Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0;
844     if (markIndex.insert(name, this, P) == 0) {
845         Msg(S_ERROR, "Error placing global bookmark %s.", name);
846     }
847     return 1;
848 }
849 
PushGlobalBookmark()850 int EBuffer::PushGlobalBookmark() {
851     EPoint P = CP;
852 
853     P.Row = VToR(P.Row);
854     EMark *m = markIndex.pushMark(this, P);
855     if (m)
856          Msg(S_INFO, "Placed bookmark %s", m->GetName());
857     return m ? 1 : 0;
858 }
859 
InsertChar(ExState & State)860 int EBuffer::InsertChar(ExState &State) {
861     char Ch;
862     int No;
863 
864     if (State.GetIntParam(View, &No) == 0) {
865         TEvent E;
866         E.What = evKeyDown;
867         E.Key.Code = View->MView->Win->GetChar("Quote Char:");
868         if (!GetCharFromEvent(E, &Ch)) return 0;
869         No = Ch;
870     }
871     if (No < 0 || No > 255) return 0;
872     Ch = char(No);
873     return InsertChar(Ch);
874 }
875 
TypeChar(ExState & State)876 int EBuffer::TypeChar(ExState &State) {
877     char Ch;
878     int No;
879 
880     if (State.GetIntParam(View, &No) == 0) {
881         TEvent E;
882         E.What = evKeyDown;
883         E.Key.Code = View->MView->Win->GetChar(0);
884         if (!GetCharFromEvent(E, &Ch)) return 0;
885         No = Ch;
886     }
887     if (No < 0 || No > 255) return 0;
888     Ch = char(No);
889     return TypeChar(Ch);
890 }
891 
InsertString(ExState & State)892 int EBuffer::InsertString(ExState &State) {
893     char strbuf[1024] = "";
894 
895     if (State.GetStrParam(View, strbuf, sizeof(strbuf)) == 0) {
896         if (View->MView->Win->GetStr("Insert String", sizeof(strbuf), strbuf, HIST_DEFAULT) == 0)
897             return 0;
898     }
899     return InsertString(strbuf, strlen(strbuf));
900 }
901 
902 extern int LastEventChar;
903 
SelfInsert(ExState &)904 int EBuffer::SelfInsert(ExState &/*State*/) {
905     if (LastEventChar != -1)
906         return TypeChar(char(LastEventChar));
907     return 0;
908 }
909 
FileReload(ExState &)910 int EBuffer::FileReload(ExState &/*State*/) {
911     if (Modified) {
912         switch (View->MView->Win->Choice(GPC_ERROR, "File Modified",
913                        2,
914                        "&Reload",
915                        "&Cancel",
916                        "%s", FileName))
917         {
918         case 0:
919             break;
920         case 1:
921         case -1:
922         default:
923             return 0;
924         }
925     }
926 //    GetNewNumber();
927     return Reload();
928 }
929 
FileSaveAs(const char * FName)930 int EBuffer::FileSaveAs(const char *FName) {
931     char Name[MAXPATH];
932 
933     if (ExpandPath(FName, Name, sizeof(Name)) == -1) {
934         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName);
935         return 0;
936     }
937     if (FindFile(Name) == 0) {
938         if (FileExists(Name)) {
939             switch (View->MView->Win->Choice(GPC_ERROR, "File Exists",
940                            2,
941                            "&Overwrite",
942                            "&Cancel",
943                            "%s", Name))
944             {
945             case 0:
946                 break;
947             case 1:
948             case -1:
949             default:
950                 return 0;
951 
952             }
953         }
954         free(FileName);
955         FileName = strdup(Name);
956         UpdateTitle();
957         return Save();
958     } else {
959         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Already editing '%s.'", Name);
960         return 0;
961     }
962 }
963 
FileSaveAs(ExState & State)964 int EBuffer::FileSaveAs(ExState &State) {
965     char FName[MAXPATH];
966 
967     strcpy(FName, FileName);
968     if (State.GetStrParam(View, FName, sizeof(FName)) == 0)
969         if (View->MView->Win->GetFile("Save As", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0)
970             return 0;
971     return FileSaveAs(FName);
972 }
973 
FileWriteTo(const char * FName)974 int EBuffer::FileWriteTo(const char *FName) {
975     char Name[MAXPATH];
976 
977     if (ExpandPath(FName, Name, sizeof(Name)) == -1) {
978         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName);
979         return 0;
980     }
981     if (FindFile(Name) == 0) {
982         if (FileExists(Name)) {
983             switch (View->MView->Win->Choice(GPC_ERROR, "File Exists",
984                            2,
985                            "&Overwrite",
986                            "&Cancel",
987                            "%s", Name))
988             {
989             case 0:
990                 break;
991             case 1:
992             case -1:
993             default:
994                 return 0;
995             }
996         }
997         return SaveTo(Name);
998     } else {
999         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Already editing '%s.'", Name);
1000         return 0;
1001     }
1002 }
1003 
FileWriteTo(ExState & State)1004 int EBuffer::FileWriteTo(ExState &State) {
1005     char FName[MAXPATH];
1006 
1007     strcpy(FName, FileName);
1008     if (State.GetStrParam(View, FName, sizeof(FName)) == 0)
1009         if (View->MView->Win->GetFile("Write To", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) return 0;
1010     return FileWriteTo(FName);
1011 }
1012 
BlockReadX(ExState & State,int blockMode)1013 int EBuffer::BlockReadX(ExState &State, int blockMode) {
1014     char Name[MAXPATH];
1015     char FName[MAXPATH];
1016 
1017     if (JustDirectory(FileName, FName, sizeof(FName)) == -1) return 0;
1018     SlashDir(FName);
1019     if (State.GetStrParam(View, FName, sizeof(FName)) == 0)
1020         if (View->MView->Win->GetFile("Read block", sizeof(FName), FName, HIST_PATH, GF_OPEN) == 0) return 0;
1021 
1022     if (ExpandPath(FName, Name, sizeof(Name)) == -1) {
1023         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName);
1024         return 0;
1025     }
1026     return BlockReadFrom(FName, blockMode);
1027 }
1028 
BlockRead(ExState & State)1029 int EBuffer::BlockRead(ExState &State) {
1030     return BlockReadX(State, BlockMode);
1031 }
1032 
BlockReadStream(ExState & State)1033 int EBuffer::BlockReadStream(ExState &State) {
1034     return BlockReadX(State, bmStream);
1035 }
1036 
BlockReadLine(ExState & State)1037 int EBuffer::BlockReadLine(ExState &State) {
1038     return BlockReadX(State, bmLine);
1039 }
1040 
BlockReadColumn(ExState & State)1041 int EBuffer::BlockReadColumn(ExState &State) {
1042     return BlockReadX(State, bmColumn);
1043 }
1044 
BlockWrite(ExState & State)1045 int EBuffer::BlockWrite(ExState &State) {
1046     char Name[MAXPATH];
1047     char FName[MAXPATH];
1048     int Append = 0;
1049 
1050     if (JustDirectory(FileName, FName, sizeof(FName)) == -1) return 0;
1051     SlashDir(FName);
1052     if (State.GetStrParam(View, FName, sizeof(FName)) == 0)
1053         if (View->MView->Win->GetFile("Write block", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0)
1054             return 0;
1055 
1056     if (ExpandPath(FName, Name, sizeof(Name)) == -1) {
1057         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName);
1058         return 0;
1059     }
1060     if (FindFile(Name) == 0) {
1061         if (FileExists(Name)) {
1062             switch (View->MView->Win->Choice(GPC_ERROR, "File Exists",
1063                            3,
1064                            "&Overwrite",
1065                            "&Append",
1066                            "&Cancel",
1067                            "%s", Name))
1068             {
1069             case 0:
1070                 break;
1071             case 1:
1072                 Append = 1;
1073                 break;
1074             case 2:
1075             case -1:
1076             default:
1077                 return 0;
1078 
1079             }
1080         }
1081     } else {
1082         View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Already editing '%s.'", Name);
1083         return 0;
1084     }
1085     return BlockWriteTo(Name, Append);
1086 }
1087 
Find(ExState & State)1088 int EBuffer::Find(ExState &State) {
1089     char find[MAXSEARCH+1] = "";
1090     char options[32] = "";
1091 
1092     if (State.GetStrParam(View, find, sizeof(find)) != 0) {
1093         if (State.GetStrParam(View, options, sizeof(options)) == 0)
1094             strcpy(options, BFS(this, BFS_DefFindOpt));
1095 
1096         LSearch.ok = 0;
1097         strcpy(LSearch.strSearch, find);
1098         LSearch.strReplace[0] = 0;
1099         LSearch.Options = 0;
1100         if (ParseSearchOptions(0, options, LSearch.Options) == 0) return 0;
1101         LSearch.ok = 1;
1102     } else if ((HaveGUIDialogs & GUIDLG_FIND) && GUIDialogs) {
1103         LSearch.ok = 0;
1104         LSearch.strSearch[0] = 0;
1105         LSearch.strReplace[0] = 0;
1106         LSearch.Options = 0;
1107         if (BFS(this, BFS_DefFindOpt))
1108             strcpy(options, BFS(this, BFS_DefFindOpt));
1109         if (ParseSearchOptions(0, options, LSearch.Options) == 0)
1110             LSearch.Options = 0;
1111 
1112         if (DLGGetFind(View->MView->Win, LSearch) == 0)
1113             return 0;
1114     } else {
1115         if (BFS(this, BFS_DefFindOpt))
1116             strcpy(options, BFS(this, BFS_DefFindOpt));
1117         if (View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH) == 0) return 0;
1118         if (View->MView->Win->GetStr("Options (All/Block/Cur/Delln/Glob/Igncase/Joinln/Rev/Word/regX)", sizeof(options), options, HIST_SEARCHOPT) == 0) return 0;
1119 
1120         LSearch.ok = 0;
1121         strcpy(LSearch.strSearch, find);
1122         LSearch.strReplace[0] = 0;
1123         LSearch.Options = 0;
1124         if (ParseSearchOptions(0, options, LSearch.Options) == 0) return 0;
1125         LSearch.ok = 1;
1126     }
1127     if (LSearch.ok == 0) return 0;
1128     LSearch.Options |= SEARCH_CENTER;
1129     if (Find(LSearch) == 0) return 0;
1130     return 1;
1131 }
1132 
FindReplace(ExState & State)1133 int EBuffer::FindReplace(ExState &State) {
1134     char find[MAXSEARCH+1] = "";
1135     char replace[MAXSEARCH+1] = "";
1136     char options[32] = "";
1137 
1138     if (State.GetStrParam(View, find, sizeof(find)) != 0) {
1139         if (State.GetStrParam(View, replace, sizeof(replace)) == 0)
1140             return 0;
1141         if (State.GetStrParam(View, options, sizeof(options)) == 0)
1142             return 0;
1143 
1144         LSearch.ok = 0;
1145         strcpy(LSearch.strSearch, find);
1146         strcpy(LSearch.strReplace, replace);
1147         LSearch.Options = 0;
1148         if (ParseSearchOptions(1, options, LSearch.Options) == 0) return 0;
1149         LSearch.Options |= SEARCH_REPLACE;
1150         LSearch.ok = 1;
1151     } else if ((HaveGUIDialogs & GUIDLG_FINDREPLACE) && GUIDialogs) {
1152         LSearch.ok = 0;
1153         LSearch.strSearch[0] = 0;
1154         LSearch.strReplace[0] = 0;
1155         LSearch.Options = 0;
1156         if (BFS(this, BFS_DefFindReplaceOpt))
1157             strcpy(options, BFS(this, BFS_DefFindReplaceOpt));
1158         if (ParseSearchOptions(1, options, LSearch.Options) == 0)
1159             LSearch.Options = 0;
1160         if (DLGGetFindReplace(View->MView->Win, LSearch) == 0)
1161             return 0;
1162     } else {
1163         if (BFS(this, BFS_DefFindReplaceOpt))
1164             strcpy(options, BFS(this, BFS_DefFindReplaceOpt));
1165         if (State.GetStrParam(View, find, sizeof(find)) == 0)
1166             if (View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH) == 0) return 0;
1167         if (State.GetStrParam(View, replace, sizeof(replace)) == 0)
1168             if (View->MView->Win->GetStr("Replace", sizeof(replace), replace, HIST_SEARCH) == 0) return 0;
1169         if (State.GetStrParam(View, options, sizeof(options)) == 0)
1170             if (View->MView->Win->GetStr("Options (All/Block/Cur/Delln/Glob/Igncase/Joinln/Rev/Noask/Word/regX)", sizeof(options), options, HIST_SEARCHOPT) == 0) return 0;
1171 
1172         LSearch.ok = 0;
1173         strcpy(LSearch.strSearch, find);
1174         strcpy(LSearch.strReplace, replace);
1175         LSearch.Options = 0;
1176         if (ParseSearchOptions(1, options, LSearch.Options) == 0) return 0;
1177         LSearch.Options |= SEARCH_REPLACE;
1178         LSearch.ok = 1;
1179     }
1180     if (LSearch.ok == 0) return 0;
1181     LSearch.Options |= SEARCH_CENTER;
1182     if (Find(LSearch) == 0) return 0;
1183     return 1;
1184 }
1185 
FindRepeat(ExState & State)1186 int EBuffer::FindRepeat(ExState &State) {
1187     if (LSearch.ok == 0) return Find(State);
1188     LSearch.Options |= SEARCH_NEXT;
1189     LSearch.Options &= ~SEARCH_GLOBAL;
1190     if (Find(LSearch) == 0) return 0;
1191     return 1;
1192 }
1193 
FindRepeatReverse(ExState & State)1194 int EBuffer::FindRepeatReverse(ExState &State) {
1195     int rc;
1196 
1197     if (LSearch.ok == 0) return Find(State);
1198     LSearch.Options |= SEARCH_NEXT;
1199     LSearch.Options &= ~SEARCH_GLOBAL;
1200     LSearch.Options ^= SEARCH_BACK;
1201     rc = Find(LSearch);
1202     LSearch.Options ^= SEARCH_BACK;
1203     return rc;
1204 }
1205 
FindRepeatOnce(ExState & State)1206 int EBuffer::FindRepeatOnce(ExState &State) {
1207     if (LSearch.ok == 0) return Find(State);
1208     LSearch.Options |= SEARCH_NEXT;
1209     LSearch.Options &= ~SEARCH_GLOBAL;
1210     LSearch.Options &= ~SEARCH_ALL;
1211     if (Find(LSearch) == 0) return 0;
1212     return 1;
1213 }
1214 
ChangeMode(ExState & State)1215 int EBuffer::ChangeMode(ExState &State) {
1216     char Mode[32] = "";
1217     int rc;
1218 
1219     if (State.GetStrParam(View, Mode, sizeof(Mode)) == 0)
1220         if (View->MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) == 0) return 0;
1221 
1222     rc = ChangeMode(Mode);
1223     FullRedraw();
1224     return rc;
1225 }
1226 
ChangeKeys(ExState & State)1227 int EBuffer::ChangeKeys(ExState &State) {
1228     int rc;
1229     char Mode[32] = "";
1230 
1231     if (State.GetStrParam(View, Mode, sizeof(Mode)) == 0)
1232         if (View->MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) == 0) return 0;
1233 
1234     rc = ChangeKeys(Mode);
1235     FullRedraw();
1236     return rc;
1237 }
1238 
ChangeFlags(ExState & State)1239 int EBuffer::ChangeFlags(ExState &State) {
1240     int rc;
1241     char Mode[32] = "";
1242 
1243     if (State.GetStrParam(View, Mode, sizeof(Mode)) == 0)
1244         if (View->MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) == 0) return 0;
1245 
1246     rc = ChangeFlags(Mode);
1247     FullRedraw();
1248     return rc;
1249 }
1250 
ChangeTabSize(ExState & State)1251 int EBuffer::ChangeTabSize(ExState &State) {
1252     int No;
1253 
1254     if (State.GetIntParam(View, &No) == 0) {
1255         char Num[10];
1256 
1257         sprintf(Num, "%d", BFI(this, BFI_TabSize));
1258         if (View->MView->Win->GetStr("TabSize", sizeof(Num), Num, HIST_SETUP) == 0) return 0;
1259         No = atol(Num);
1260     }
1261     if (No < 1) return 0;
1262     if (No > 32) return 0;
1263     BFI(this, BFI_TabSize) = No;
1264     FullRedraw();
1265     return 1;
1266 }
1267 
SetIndentWithTabs(ExState & State)1268 int EBuffer::SetIndentWithTabs(ExState &State) {
1269     int No;
1270 
1271     if (State.GetIntParam(View, &No) == 0) return 0;
1272     Flags.num[BFI_IndentWithTabs] = No ? 1 : 0;
1273     return 1;
1274 }
1275 
ChangeRightMargin(ExState & State)1276 int EBuffer::ChangeRightMargin(ExState &State) {
1277     char Num[10];
1278     int No;
1279 
1280     if (State.GetIntParam(View, &No) == 0) {
1281         sprintf(Num, "%d", BFI(this, BFI_RightMargin) + 1);
1282         if (View->MView->Win->GetStr("RightMargin", sizeof(Num), Num, HIST_SETUP) == 0) return 0;
1283         No = atol(Num) - 1;
1284     }
1285     if (No <= 1) return 0;
1286     BFI(this, BFI_RightMargin) = No;
1287     Msg(S_INFO, "RightMargin set to %d.", No + 1);
1288     return 1;
1289 }
1290 
ChangeLeftMargin(ExState & State)1291 int EBuffer::ChangeLeftMargin(ExState &State) {
1292     char Num[10];
1293     int No;
1294 
1295     if (State.GetIntParam(View, &No) == 0) {
1296         sprintf(Num, "%d", BFI(this, BFI_LeftMargin) + 1);
1297         if (View->MView->Win->GetStr("LeftMargin", sizeof(Num), Num, HIST_SETUP) == 0) return 0;
1298         No = atol(Num) - 1;
1299     }
1300     if (No < 0) return 0;
1301     BFI(this, BFI_LeftMargin) = No;
1302     Msg(S_INFO, "LeftMargin set to %d.", No + 1);
1303     return 1;
1304 }
1305 
1306 
CanQuit()1307 int EBuffer::CanQuit() {
1308     if (Modified)
1309         return 0;
1310     else
1311         return 1;
1312 }
1313 
ConfQuit(GxView * V,int multiFile)1314 int EBuffer::ConfQuit(GxView *V, int multiFile) {
1315     if (Modified) {
1316         if (multiFile) {
1317             switch (V->Choice(GPC_ERROR,
1318                               "File Modified",
1319                               5,
1320                               "&Save",
1321                               "&As",
1322                               "A&ll",
1323                               "&Discard",
1324                               "&Cancel",
1325                               "%s", FileName))
1326             {
1327             case 0: /* Save */
1328                 if (Save() == 0) return 0;
1329                 break;
1330             case 1: /* As */
1331                 {
1332                     char FName[MAXPATH];
1333                     strcpy(FName, FileName);
1334                     if (V->GetFile("Save As", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) return 0;
1335                     if (FileSaveAs(FName) == 0) return 0;
1336                 }
1337                 break;
1338             case 2: /* Save all */
1339                 return -2;
1340             case 3: /* Discard */
1341                 break;
1342             case 4: /* Cancel */
1343             case -1:
1344             default:
1345                 return 0;
1346             }
1347         }else {
1348             switch (V->Choice(GPC_ERROR,
1349                               "File Modified",
1350                               4,
1351                               "&Save",
1352                               "&As",
1353                               "&Discard",
1354                               "&Cancel",
1355                               "%s", FileName))
1356             {
1357             case 0: /* Save */
1358                 if (Save() == 0) return 0;
1359                 break;
1360             case 1: /* As */
1361                 {
1362                     char FName[MAXPATH];
1363                     strcpy(FName, FileName);
1364                     if (V->GetFile("Save As", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) return 0;
1365                     if (FileSaveAs(FName) == 0) return 0;
1366                 }
1367                 break;
1368             case 2: /* Discard */
1369                 break;
1370             case 3: /* Cancel */
1371             case -1:
1372             default:
1373                 return 0;
1374             }
1375         }
1376     }
1377     return 1;
1378 }
1379 
GetName(char * AName,size_t MaxLen)1380 void EBuffer::GetName(char *AName, size_t MaxLen) {
1381     strlcpy(AName, FileName, MaxLen);
1382 }
1383 
GetPath(char * APath,size_t MaxLen)1384 void EBuffer::GetPath(char *APath, size_t MaxLen) {
1385     JustDirectory(FileName, APath, MaxLen);
1386 }
1387 
GetInfo(char * AInfo,size_t)1388 void EBuffer::GetInfo(char *AInfo, size_t /*MaxLen*/) {
1389     char buf[256] = {0};
1390     char winTitle[256] = {0};
1391 
1392     JustFileName(FileName, buf, sizeof(buf));
1393     if (buf[0] == '\0') // if there is no filename, try the directory name.
1394         JustLastDirectory(FileName, buf, sizeof(buf));
1395 
1396     if (buf[0] != 0) // if there is a file/dir name, stick it in here.
1397     {
1398         strlcat(winTitle, buf, sizeof(winTitle));
1399         strlcat(winTitle, " - ", sizeof(winTitle));
1400     }
1401     strlcat(winTitle, FileName, sizeof(winTitle));
1402 
1403     sprintf(AInfo,
1404             "%2d %04d:%03d%c%-150s ",
1405             ModelNo,
1406             1 + CP.Row, 1 + CP.Col,
1407             Modified ? '*': ' ',
1408             winTitle);
1409 }
1410 
GetTitle(char * ATitle,size_t MaxLen,char * ASTitle,size_t SMaxLen)1411 void EBuffer::GetTitle(char *ATitle, size_t MaxLen, char *ASTitle, size_t SMaxLen) {
1412 
1413     strlcpy(ATitle, FileName, MaxLen);
1414     char *p = SepRChr(FileName);
1415     strlcpy(ASTitle, (p) ? p + 1 : FileName, SMaxLen);
1416 }
1417 
1418 #ifdef CONFIG_I_ASCII
ASCIITable(ExState &)1419 int EBuffer::ASCIITable(ExState &/*State*/) {
1420     int rc;
1421 
1422     rc = View->MView->Win->PickASCII();
1423     if (rc != -1)
1424         return InsertChar(char(rc));
1425 
1426     return 0;
1427 }
1428 #endif
1429 
ScrollLeft(ExState & State)1430 int EBuffer::ScrollLeft(ExState &State) {
1431     int Cols;
1432 
1433     if (State.GetIntParam(View, &Cols) == 0)
1434         Cols = 8;
1435     return ScrollLeft(Cols);
1436 }
1437 
ScrollRight(ExState & State)1438 int EBuffer::ScrollRight(ExState &State) {
1439     int Cols;
1440 
1441     if (State.GetIntParam(View, &Cols) == 0)
1442         Cols = 8;
1443     return ScrollRight(Cols);
1444 }
1445 
ScrollDown(ExState & State)1446 int EBuffer::ScrollDown(ExState &State) {
1447     int Rows;
1448 
1449     if (State.GetIntParam(View, &Rows) == 0)
1450         Rows = 1;
1451     return ScrollDown(Rows);
1452 }
1453 
ScrollUp(ExState & State)1454 int EBuffer::ScrollUp(ExState &State) {
1455     int Rows;
1456 
1457     if (State.GetIntParam(View, &Rows) == 0)
1458         Rows = 1;
1459     return ScrollUp(Rows);
1460 }
1461 
1462 #ifdef CONFIG_TAGS
FindTag(ExState & State)1463 int EBuffer::FindTag(ExState &State) {
1464     char Tag[MAXSEARCH] = "";
1465 
1466     if (State.GetStrParam(View, Tag, sizeof(Tag)) == 0)
1467         if (View->MView->Win->GetStr("Find tag", sizeof(Tag), Tag, HIST_SEARCH) == 0) return 0;
1468 
1469     int j = 2;
1470     while (j--) {
1471         int i;
1472 
1473         i = TagFind(this, View, Tag);
1474         if (i > 0)
1475             return 1;
1476         else if (j && (i < 0)) {
1477             /* Try autoload tags */
1478             if (View->ExecCommand(ExTagLoad, State) == 0)
1479                 break;
1480         } else {
1481             Msg(S_INFO, "Tag '%s' not found.", Tag);
1482             break;
1483         }
1484     }
1485     return 0;
1486 
1487 }
1488 #endif
1489 
1490 // these two will probably be replaced in the future
InsertDate(ExState & State)1491 int EBuffer::InsertDate(ExState &State) {
1492     char strArg[128] = "";
1493     char buf[128], *p;
1494 
1495     time_t t;
1496 
1497     time(&t);
1498 
1499     if (State.GetStrParam(View, strArg, sizeof(strArg))) {
1500         struct tm *tt = localtime(&t);
1501         strftime(buf, sizeof(buf), strArg, tt);
1502         buf[sizeof(buf) - 1] = 0;
1503     } else {
1504         //** 012345678901234567890123
1505         //** Wed Jan 02 02:23:54 1991
1506         p = ctime(&t);
1507         sprintf(buf, "%.10s %.4s", p, p + 20);
1508     }
1509     //puts(buf);
1510 
1511     return InsertString(buf, strlen(buf));
1512 }
1513 
1514 
InsertUid()1515 int EBuffer::InsertUid() {
1516     const char *p = getenv("USER");
1517     if (p == 0) p = getenv("NAME");
1518     if (p == 0) p = getenv("ID");
1519     // mostly for Windows.  Why they can't just be standard, I don't know...
1520     if (p == 0) p = getenv("USERNAME");
1521     if (p == 0) {
1522         Msg(S_INFO, "User ID not set ($USER).");
1523         //return 0;
1524 	p = "UNKNOWN USER";
1525     }
1526     return InsertString(p, strlen(p));
1527 }
1528 
ShowHelpWord(ExState & State)1529 int EBuffer::ShowHelpWord(ExState &State) {
1530     //** Code for BlockSelectWord to find the word under the cursor,
1531     const char *achr = "+-_."; // these are accepted characters
1532     char    buf[128];
1533     int     Y = VToR(CP.Row);
1534     PELine  L = RLine(Y);
1535     int     P;
1536 
1537     P = CharOffset(L, CP.Col);
1538 
1539     // fix \b for the case of CATBS
1540     for(int i = 0; i < P; i++) {
1541         //printf("%d - %d  %d   %c %c\n", i, P, L->Chars[i],
1542         //L->Chars[i], L->Chars[P]);
1543         if ((L->Chars[i] == '\b') && (P < (L->Count - 2)))
1544             P += 2;
1545     }
1546     size_t len = 0;
1547     if (P < L->Count) {
1548         // To start of word,
1549         while ((P > 0)
1550                && ((L->Chars[P - 1] == '\b') || isalnum(L->Chars[P - 1])
1551                    || (strchr(achr, L->Chars[P - 1]) != NULL)))
1552             P--; // '_' for underline is hidden in achr
1553         if ((P < (L->Count - 1)) && (L->Chars[P] == '\b'))
1554             P++;
1555         // To end of word,
1556         while ((len < (sizeof(buf) - 1)) && (P < L->Count)) {
1557             if (((P + 1) < L->Count) && (L->Chars[P + 1] == '\b'))
1558                 P += 2;
1559             else if (isalnum(L->Chars[P])
1560                      || (strchr(achr, L->Chars[P]) != NULL))
1561                 buf[len++] = L->Chars[P++];
1562             else
1563                 break;
1564         }
1565     }
1566     buf[len] = 0;
1567     //printf("Word: %s\n", buf);
1568     //if (buf[0] == 0) {
1569     //    Msg(INFO, "No valid word under the cursor.");
1570     //    return 0;
1571     //}
1572     return View->SysShowHelp(State, buf[0] ? buf : 0);
1573 }
1574 
GetStrVar(int var,char * str,size_t buflen)1575 int EBuffer::GetStrVar(int var, char *str, size_t buflen) {
1576     if (buflen == 0)
1577         return 0;
1578     //puts("variable EBuffer\x7");
1579     switch (var) {
1580     case mvFilePath:
1581         //puts("variable FilePath\x7");
1582         strncpy(str, FileName, buflen);
1583         str[buflen - 1] = 0;
1584         return 1;
1585 
1586     case mvFileName:
1587         JustFileName(FileName, str, buflen);
1588         return 1;
1589 
1590     case mvFileDirectory:
1591         JustDirectory(FileName, str, buflen);
1592         return 1;
1593     case mvFileBaseName:
1594         {
1595             char buf[MAXPATH];
1596             char *dot, *dot2;
1597 
1598             JustFileName(FileName, buf, sizeof(buf));
1599 
1600             dot = strchr(buf, '.');
1601             while ((dot2 = strchr(dot + 1, '.')) != NULL)
1602                 dot = dot2;
1603             if (dot)
1604                 *dot = 0;
1605             strlcpy(str, buf, buflen);
1606         }
1607         return 1;
1608 
1609     case mvFileExtension:
1610         {
1611             char buf[MAXPATH];
1612             char *dot;
1613 
1614             JustFileName(FileName, buf, sizeof(buf));
1615 
1616             dot = strrchr(buf, '.');
1617             if (dot)
1618                 strlcpy(str, dot, buflen);
1619             else
1620                 str[0] = 0;
1621         }
1622         return 1;
1623 
1624     case mvChar:
1625         {
1626             PELine L;
1627             int P;
1628 
1629             L = RLine(CP.Row);
1630             P = CharOffset(L, CP.Col);
1631 
1632             strlcpy(str, "", buflen);
1633 
1634             if (ChClass(L->Chars[P]))
1635             {
1636                 char tmp[2];
1637 
1638                 // make copy of character
1639                 tmp[0] = L->Chars[P];
1640                 tmp[1] = 0;
1641 
1642                 strlcat(str, tmp, buflen);
1643             }
1644         }
1645         return 1;
1646 
1647     case mvWord:
1648         {
1649             PELine L;
1650             int P, C;
1651             int wordBegin, wordEnd;
1652 
1653             L = RLine(CP.Row);
1654             P = CharOffset(L, CP.Col);
1655 
1656             strlcpy(str, "", buflen);
1657 
1658             if (ChClass(L->Chars[P]))
1659             {
1660                 C = ChClassK(L->Chars[P]);
1661 
1662                 // search start of word
1663                 while ((P>0) && (C == ChClassK(L->Chars[P-1]))) P--;
1664 
1665                 wordBegin = P;
1666 
1667                 // search end of word
1668                 while ((P< L->Count) && (C == ChClassK(L->Chars[P]))) P++;
1669 
1670                 wordEnd = P;
1671 
1672                 // calculate total length for buffer copy
1673                 size_t length = wordEnd - wordBegin;
1674 
1675                 if ((length + 1) < buflen)
1676                 {
1677                     length++;
1678                 } else
1679                 {
1680                     length = buflen;
1681                 }
1682 
1683                 // copy word to buffer
1684                 strlcpy(str, &L->Chars[wordBegin], length);
1685             }
1686         }
1687         return 1;
1688 
1689     case mvLine:
1690         {
1691             PELine L;
1692 
1693             L = RLine(CP.Row);
1694 
1695             strlcpy(str, "", buflen);
1696 
1697             if (L->Count > 0)
1698             {
1699                 // calculate total length for buffer copy
1700                 size_t length = L->Count;
1701 
1702                 if ((length + 1) < buflen)
1703                 {
1704                     length++;
1705                 } else
1706                 {
1707                     length = buflen;
1708                 }
1709 
1710                 // copy word to buffer
1711                 strlcpy(str, L->Chars, length);
1712             }
1713         }
1714         return 1;
1715 
1716     case mvFTEVer:
1717         strlcpy(str, VERSION, buflen);
1718         return 1;
1719     }
1720 
1721     return EModel::GetStrVar(var, str, buflen);
1722 }
1723 
GetIntVar(int var,int * value)1724 int EBuffer::GetIntVar(int var, int *value) {
1725     switch (var) {
1726     case mvCurRow: *value = VToR(CP.Row) + 1; return 1;
1727     case mvCurCol: *value = CP.Col; return 1;
1728     }
1729     return EModel::GetIntVar(var, value);
1730 }
1731