1 /*    o_buflist.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 
11 #include "o_buflist.h"
12 
13 #include "i_modelview.h"
14 #include "i_view.h"
15 #include "s_string.h"
16 #include "s_util.h"
17 #include "sysdep.h"
18 
19 #include <stdio.h>
20 
21 BufferView *BufferList = 0;
22 
BufferView(int createFlags,EModel ** ARoot)23 BufferView::BufferView(int createFlags, EModel **ARoot) :
24     EList(createFlags, ARoot, "Buffers"),
25     BList(0),
26     BCount(0),
27     SearchLen(0)
28 {
29     ModelNo = 0; // trick
30 }
31 
~BufferView()32 BufferView::~BufferView() {
33     if (BList) {
34         for (int i = 0; i < BCount; i++)
35             if (BList[i])
36                 free(BList[i]);
37         free(BList);
38     }
39     BufferList = 0;
40 }
41 
GetEventMap()42 EEventMap *BufferView::GetEventMap() {
43     return FindEventMap("BUFFERS");
44 }
45 
GetContext()46 int BufferView::GetContext() {
47     return CONTEXT_BUFFERS;
48 }
49 
DrawLine(PCell B,int Line,int Col,ChColor color,int Width)50 void BufferView::DrawLine(PCell B, int Line, int Col, ChColor color, int Width) {
51     if (Line < BCount)
52         if (Col < int(strlen(BList[Line])))
53             MoveStr(B, 0, Width, BList[Line] + Col, color, Width);
54 }
55 
FormatLine(int Line)56 char* BufferView::FormatLine(int Line) {
57     return strdup(BList[Line]);
58 }
59 
UpdateList()60 void BufferView::UpdateList() {
61     EModel *B = ActiveModel;
62     int No;
63     char s[512] = "";
64 
65     if (BList) {
66         for (int i = 0; i < BCount; i++)
67             if (BList[i])
68                 free(BList[i]);
69         free(BList);
70     }
71     BList = 0;
72     BCount = 0;
73     while (B) {
74         BCount++;
75         B = B->Next;
76         if (B == ActiveModel) break;
77     }
78     BList = (char **) malloc(sizeof(char *) * BCount);
79     assert(BList != 0);
80     B = ActiveModel;
81     No = 0;
82     while (B) {
83         B->GetInfo(s, sizeof(s) - 1);
84         BList[No++] = strdup(s);
85         B = B->Next;
86         if (B == ActiveModel) break;
87         if (No >= BCount) break;
88     }
89     Count = BCount;
90     NeedsUpdate = 1;
91 }
92 
GetBufferById(int No)93 EModel *BufferView::GetBufferById(int No) {
94     EModel *B;
95 
96     B = ActiveModel;
97     while (B) {
98         if (No == 0) {
99             return B;
100         }
101         No--;
102         B = B->Next;
103         if (B == ActiveModel) break;
104     }
105     return 0;
106 }
107 
ExecCommand(ExCommands Command,ExState & State)108 int BufferView::ExecCommand(ExCommands Command, ExState &State) {
109 
110     switch (Command) {
111     case ExCloseActivate:
112         {
113             EModel *B;
114 
115             CancelSearch();
116             B = GetBufferById(Row);
117             if (B && B != this) {
118                 View->SwitchToModel(B);
119                 delete this;
120                 return 1;
121             }
122         }
123         return 0;
124     case ExBufListFileClose:
125         {
126             EModel *B = GetBufferById(Row);
127 
128             CancelSearch();
129             if (B && B != this && Count > 1) {
130                 if (B->ConfQuit(View->MView->Win)) {
131                     View->DeleteModel(B);
132                 }
133                 UpdateList();
134                 return 1;
135             }
136         }
137         return 0;
138     case ExBufListFileSave:
139         {
140             EModel *B = GetBufferById(Row);
141 
142             if (B && B->GetContext() == CONTEXT_FILE)
143                 if (((EBuffer *)B)->Save())
144                     return 1;
145         }
146         return 0;
147 
148     case ExActivateInOtherWindow:
149         {
150             EModel *B = GetBufferById(Row);
151 
152             CancelSearch();
153             if (B) {
154                 View->Next->SwitchToModel(B);
155                 return 1;
156             }
157         }
158         return 0;
159     case ExBufListSearchCancel:
160         CancelSearch();
161         return 1;
162     case ExBufListSearchNext:
163         // Find next matching line
164         if (SearchLen) {
165             int i = Row + 1;
166             i = getMatchingLine(i == BCount ? 0 : i, 1);
167             // Never returns -1 since something already found before call
168             Row = SearchPos[SearchLen] = i;
169         }
170         return 1;
171     case ExBufListSearchPrev:
172         // Find prev matching line
173         if (SearchLen) {
174             int i = Row - 1;
175             i = getMatchingLine(i == -1 ? BCount - 1 : i, -1);
176             // Never returns -1 since something already found before call
177             Row = SearchPos[SearchLen] = i;
178         }
179         return 1;
180     default:
181         ;
182     }
183     return EList::ExecCommand(Command, State);
184 }
185 
HandleEvent(TEvent & Event)186 void BufferView::HandleEvent(TEvent &Event) {
187     int resetSearch = 1;
188     EModel::HandleEvent(Event);
189     switch (Event.What) {
190         case evKeyUp:
191             resetSearch = 0;
192             break;
193         case evKeyDown:
194             switch (kbCode(Event.Key.Code)) {
195                 case kbBackSp:
196                     resetSearch = 0;
197                     if (SearchLen > 0) {
198                         SearchString[--SearchLen] = 0;
199                         Row = SearchPos[SearchLen];
200                         Msg(S_INFO, "Search: [%s]", SearchString);
201                     } else
202                         Msg(S_INFO, "");
203                     break;
204                 case kbEsc:
205                     Msg(S_INFO, "");
206                     break;
207                 default:
208                     resetSearch = 0;
209                     if (isAscii(Event.Key.Code) && (SearchLen < ExISearch::MAXISEARCH)) {
210                         char Ch = (char) Event.Key.Code;
211 
212                         SearchPos[SearchLen] = Row;
213                         SearchString[SearchLen] = Ch;
214                         SearchString[++SearchLen] = 0;
215                         int i = getMatchingLine(Row, 1);
216                         if (i == -1)
217                             SearchString[--SearchLen] = 0;
218                         else
219                             Row = i;
220                         Msg(S_INFO, "Search: [%s]", SearchString);
221                     }
222                     break;
223             }
224     }
225     if (resetSearch)
226         SearchLen = 0;
227 }
228 
229 /**
230  * Search for next line containing SearchString starting from line 'start'.
231  * Direction should be 1 for ascending and -1 for descending.
232  * Returns line found or -1 if none.
233  */
getMatchingLine(int start,int direction)234 int BufferView::getMatchingLine (int start, int direction) {
235     int i = start;
236     do {
237         // Find SearchString at any place in string for line i
238         for(int j = 0; BList[i][j]; j++)
239             if (BList[i][j] == SearchString[0] && strnicmp(SearchString, BList[i]+j, SearchLen) == 0) {
240                 return i;
241             }
242         i += direction;
243         if (i == BCount) i = 0; else if (i == -1) i = BCount - 1;
244     } while (i != start);
245     return -1;
246 }
247 
Activate(int No)248 int BufferView::Activate(int No) {
249     EModel *B;
250 
251     CancelSearch();
252     B = GetBufferById(No);
253     if (B) {
254         View->SwitchToModel(B);
255         return 1;
256     }
257     return 0;
258 }
259 
CancelSearch()260 void BufferView::CancelSearch() {
261     SearchLen = 0;
262     Msg(S_INFO, "");
263 }
264 
GetInfo(char * AInfo,size_t MaxLen)265 void BufferView::GetInfo(char *AInfo, size_t MaxLen) {
266     snprintf(AInfo, MaxLen, "%2d %04d/%03d Buffers", ModelNo, Row + 1, Count);
267 }
268 
GetTitle(char * ATitle,size_t MaxLen,char * ASTitle,size_t SMaxLen)269 void BufferView::GetTitle(char *ATitle, size_t MaxLen, char *ASTitle, size_t SMaxLen) {
270     strlcpy(ATitle, "Buffers", MaxLen);
271     strlcpy(ASTitle, "Buffers", SMaxLen);
272 }
273