- Update to r53061
[reactos.git] / base / applications / network / telnet / src / tscroll.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998-2000 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
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
9 //as published by the Free Software Foundation; either version 2
10 //of the 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
15 //GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
24 ///////////////////////////////////////////////////////////////////////////
25
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // Module: tscroll.cpp
29 //
30 // Contents: Telnet Handler
31 //
32 // Product: telnet
33 //
34 // Revisions: Dec. 5, 1998 Paul Brannan <pbranna@clemson.edu>
35 // June 15, 1998 Paul Brannan
36 //
37 // This is code originally from tnclass.cpp and ansiprsr.cpp
38 //
39 ///////////////////////////////////////////////////////////////////////////////
40
41 #include "precomp.h"
42
43 enum {
44 HEX,
45 DUMP,
46 DUMPB,
47 TEXTB,
48 };
49
50 int DummyStripBuffer(char *start, char *end, int width) {return 0;}
51
52 TScroller::TScroller(TMouse &M, int size) : Mouse(M) {
53 iScrollSize = size;
54 pcScrollData = new char[iScrollSize];
55 iScrollEnd = 0;
56 iPastEnd = 0;
57 memset(pcScrollData, ' ', iScrollSize);
58
59 if(stricmp(ini.get_scroll_mode(), "hex") == 0) iDisplay = HEX;
60 else if(stricmp(ini.get_scroll_mode(), "dump") == 0) iDisplay = DUMP;
61 else if(stricmp(ini.get_scroll_mode(), "dumpb") == 0) iDisplay = DUMPB;
62 else if(stricmp(ini.get_scroll_mode(), "text") == 0) iDisplay = TEXTB;
63 else iDisplay = DUMP;
64
65 strip = &DummyStripBuffer;
66 }
67
68 TScroller::~TScroller() {
69 delete[] pcScrollData;
70 }
71
72 void TScroller::init(stripfunc *s) {
73 strip = s;
74 }
75
76 // Fixed update of circular buffer (Paul Brannan 12/4/98)
77 // Note: iScrollEnd is one character beyond the end
78 void TScroller::update(const char *pszHead, const char *pszTail) {
79 if ((iScrollEnd)+(pszTail-pszHead) < iScrollSize) {
80 memcpy(&pcScrollData[iScrollEnd], pszHead, pszTail-pszHead);
81 } else if (pszTail-pszHead > iScrollSize) {
82 memcpy(pcScrollData, pszTail-iScrollSize, iScrollSize);
83 iScrollEnd = 0;
84 } else {
85 memcpy(&pcScrollData[iScrollEnd], pszHead, iScrollSize-iScrollEnd);
86 memcpy(&pcScrollData[0], pszHead + (iScrollSize-iScrollEnd),
87 pszTail-pszHead-(iScrollSize-iScrollEnd));
88 }
89
90 // This could probably be optimized better, but it's probably not worth it
91 int temp = iScrollEnd;
92 iScrollEnd = ((iScrollEnd)+(pszTail-pszHead))%iScrollSize;
93 if(iScrollEnd < temp) iPastEnd = 1;
94 }
95
96 // Perhaps this should be moved to Tconsole.cpp? (Paul Brannan 6/12/98)
97 static BOOL WriteConsoleOutputCharAndAttribute(
98 HANDLE hConsoleOutput, // handle of a console screen buffer
99 CHAR * lpWriteBuffer,
100 WORD wAttrib,
101 SHORT sX,
102 SHORT sY ){
103 // we ought to allocate memory before writing to an address (PB 5/12/98)
104 DWORD cWritten;
105 const LPDWORD lpcWritten = &cWritten;
106
107 DWORD cWriteCells = strlen(lpWriteBuffer);
108 COORD coordWrite = {sX,sY};
109 LPWORD lpwAttribute = new WORD[cWriteCells];
110 for (unsigned int i = 0; i < cWriteCells; i++)
111 lpwAttribute[i] = wAttrib;
112 WriteConsoleOutputAttribute(
113 hConsoleOutput, // handle of a console screen buffer
114 lpwAttribute, // address of buffer to write attributes from
115 cWriteCells, // number of character cells to write to
116 coordWrite, // coordinates of first cell to write to
117 lpcWritten // address of number of cells written to
118 );
119 WriteConsoleOutputCharacter(
120 hConsoleOutput, // handle of a console screen buffer
121 lpWriteBuffer, // address of buffer to write characters from
122 cWriteCells, // number of character cells to write to
123 coordWrite, // coordinates of first cell to write to
124 lpcWritten // address of number of cells written to
125 );
126 delete [] lpwAttribute;
127 return 1;
128 }
129
130 static void hexify(int x, char *str, int len) {
131 for(int j = len - 1; j >= 0; j--) {
132 str[j] = x % 16;
133 if(str[j] > 9) str[j] += 'A' - 10;
134 else str[j] += '0';
135 x /= 16;
136 }
137 }
138
139 static int setmaxlines(int iDisplay, int iScrollSize, int strippedlines,
140 int con_width) {
141 switch(iDisplay) {
142 case HEX: return(iScrollSize / 16); break;
143 case DUMP:
144 case DUMPB: return(iScrollSize / con_width); break;
145 case TEXTB: return(strippedlines); break;
146 }
147 return 0;
148 }
149
150 static void setstatusline(char *szStatusLine, int len, int iDisplay) {
151 memset(szStatusLine, ' ', len);
152 memcpy(&szStatusLine[1], "Scrollback Mode", 15);
153 switch(iDisplay) {
154 case HEX: memcpy(&szStatusLine[len / 2 - 1], "HEX", 3); break;
155 case DUMP: memcpy(&szStatusLine[len / 2 - 2], "DUMP", 4); break;
156 case DUMPB: memcpy(&szStatusLine[len / 2 - 5], "BINARY DUMP", 11); break;
157 case TEXTB: memcpy(&szStatusLine[len / 2 - 2], "TEXT", 4); break;
158 }
159 memcpy(&szStatusLine[len - 6], "READY", 5);
160 szStatusLine[len] = 0;
161 }
162
163 void TScroller::ScrollBack(){
164 char p;
165 int r,c;
166
167 // define colors (Paul Brannan 7/5/98)
168 int normal = (ini.get_scroll_bg() << 4) | ini.get_scroll_fg();
169 // int inverse = (ini.get_scroll_fg() << 4) | ini.get_scroll_bg();
170 int status = (ini.get_status_bg() << 4) | ini.get_status_fg();
171
172 CHAR_INFO* chiBuffer;
173 chiBuffer = newBuffer();
174 saveScreen(chiBuffer);
175
176 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
177 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
178 GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
179
180 // Update iScrollBegin -- necessary in case the buffer isn't full yet
181 long iScrollBegin, iScrollLast;
182 if(iPastEnd == 0) {
183 iScrollBegin = 0;
184 iScrollLast = iScrollEnd - 1;
185 } else {
186 iScrollBegin = iScrollEnd;
187 iScrollLast = iScrollSize - 1;
188 }
189
190 // Create buffer with ANSI codes stripped
191 // Fixed this to work properly with a circular buffer (PB 12/4/98)
192 char *stripped = new char[iScrollSize];
193 memcpy(stripped, pcScrollData + iScrollBegin, iScrollSize -
194 iScrollBegin);
195 if(iScrollBegin != 0) memcpy(stripped + (iScrollSize - iScrollBegin),
196 pcScrollData, iScrollBegin - 1);
197 int strippedlines = (*strip)(stripped, stripped + iScrollLast,
198 CON_COLS);
199
200 // Calculate the last line of the scroll buffer (Paul Brannan 12/4/98)
201 int maxlines = setmaxlines(iDisplay, iScrollLast + 1, strippedlines,
202 CON_COLS);
203
204 // init scroll position
205 int current = maxlines - CON_HEIGHT + 1;
206 if(current < 0) current = 0;
207
208 // paint border and info
209 // paint last two lines black on white
210 char * szStatusLine;
211 szStatusLine = new char[CON_WIDTH+2];
212 setstatusline(szStatusLine, CON_COLS, iDisplay);
213 WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine, status,
214 CON_LEFT, CON_BOTTOM);
215
216 // loop while not done
217 BOOL done = FALSE;
218 while (!done){
219 switch (iDisplay){
220 case HEX:
221 memset(szStatusLine, ' ', CON_COLS);
222 szStatusLine[8] = ':';
223 szStatusLine[34] = '-';
224 for (r = 0; r < CON_HEIGHT; r++) {
225 hexify((r + current) * 16, &szStatusLine[2], 6);
226 for (c = 0; c < 16; c++){
227 if (c+(16*(r+current)) >= iScrollLast)
228 p = 0;
229 else
230 p = pcScrollData[(c+16*(r+current) + iScrollBegin) %
231 iScrollSize];
232 hexify((char)p, &szStatusLine[11 + 3*c], 2);
233 if (!iscntrl(p)) {
234 szStatusLine[60 + c] = (char)p;
235 } else {
236 szStatusLine[60 + c] = '.';
237 }
238 }
239 for(int j = 0; j < 16; j++) {
240 }
241 szStatusLine[CON_COLS] = '\0';
242 WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
243 normal, CON_LEFT, r+CON_TOP);
244 }
245 break;
246 case DUMP:
247 for (r = 0; r < CON_HEIGHT; r++) {
248 for (c = 0; c <= CON_WIDTH; c++) {
249 if (c+((CON_COLS)*(r+current)) >= iScrollLast) p = ' ';
250 else p = pcScrollData[(c+((CON_COLS)*(r+current))
251 + iScrollBegin) % iScrollSize];
252 if (!iscntrl(p))
253 szStatusLine[c] = p;
254 else
255 szStatusLine[c] = '.';
256 }
257 szStatusLine[c] = '\0';
258 WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
259 normal, CON_LEFT, r+CON_TOP);
260 }
261 break;
262 case DUMPB:
263 for (r = 0; r < CON_HEIGHT; r++) {
264 for (c = 0; c <= CON_WIDTH; c++) {
265 if (c+((CON_COLS)*(r+current)) >= iScrollLast) p = ' ';
266 else p = pcScrollData[ (c+((CON_COLS)*(r+current))
267 + iScrollBegin) % iScrollSize];
268 if (p != 0)
269 szStatusLine[c] = p;
270 else
271 szStatusLine[c] = ' ';
272 }
273 szStatusLine[c] = '\0';
274 WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
275 normal, CON_LEFT, r+CON_TOP);
276 }
277 break;
278 case TEXTB: {
279 int ch, lines, x;
280 // Find the starting position
281 for(ch = 0, lines = 0, x = 1; ch < iScrollSize &&
282 lines < current; ch++, x++) {
283
284 if(stripped[ch] == '\n') lines++;
285 if(stripped[ch] == '\r') x = 1;
286 }
287
288 for (r = 0; r < CON_HEIGHT; r++) {
289 memset(szStatusLine, ' ', CON_COLS);
290 for(c = 0; c <= CON_WIDTH; c++) {
291 done = FALSE;
292 if (ch >= iScrollSize) p = ' ';
293 else p = stripped[ch];
294 switch(p) {
295 case 10: done = TRUE; break;
296 case 13: c = 0; break;
297 default: szStatusLine[c] = p;
298 }
299 ch++;
300 if(done) break;
301 }
302 szStatusLine[CON_COLS] = '\0';
303 WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
304 normal, CON_LEFT, r+CON_TOP);
305 }
306 }
307 break;
308 }
309
310 setstatusline(szStatusLine, CON_COLS, iDisplay);
311 WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine, status,
312 CON_LEFT, CON_BOTTOM);
313
314 // paint scroll back data
315 // get key input
316 switch(scrollkeys()){
317 case VK_ESCAPE:
318 done = TRUE;
319 break;
320 case VK_PRIOR:
321 if ( current > CON_HEIGHT)
322 current-= CON_HEIGHT;
323 else
324 current = 0;
325 break;
326 case VK_NEXT:
327 if ( current < maxlines - 2*CON_HEIGHT + 2)
328 current += CON_HEIGHT;
329 else
330 current = maxlines - CON_HEIGHT + 1;
331 break;
332 case VK_DOWN:
333 if (current <= maxlines - CON_HEIGHT) current++;
334 break;
335 case VK_UP:
336 if ( current > 0) current--;
337 break;
338 case VK_TAB:
339 iDisplay = (iDisplay+1)%4;
340 maxlines = setmaxlines(iDisplay, iScrollLast + 1, strippedlines,
341 CON_COLS);
342 if(current > maxlines) current = maxlines - 1;
343 if(current < 0) current = 0;
344 break;
345 case VK_END:
346 current = maxlines - CON_HEIGHT + 1;
347 if(current < 0) current = 0;
348 break;
349 case VK_HOME:
350 current = 0;
351 break;
352 case SC_MOUSE:
353 Mouse.scrollMouse();
354 break;
355 }
356 }
357
358 // Clean up
359 restoreScreen(chiBuffer);
360 delete[] szStatusLine;
361 delete[] chiBuffer;
362 delete[] stripped;
363 }