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