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
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.
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.
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.
24 ///////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////
28 // Module: tscroll.cpp
30 // Contents: Telnet Handler
34 // Revisions: Dec. 5, 1998 Paul Brannan <pbranna@clemson.edu>
35 // June 15, 1998 Paul Brannan
37 // This is code originally from tnclass.cpp and ansiprsr.cpp
39 ///////////////////////////////////////////////////////////////////////////////
50 int DummyStripBuffer(char *start
, char *end
, int width
) {return 0;}
52 TScroller::TScroller(TMouse
&M
, int size
) : Mouse(M
) {
54 pcScrollData
= new char[iScrollSize
];
57 memset(pcScrollData
, ' ', iScrollSize
);
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
;
65 strip
= &DummyStripBuffer
;
68 TScroller::~TScroller() {
69 delete[] pcScrollData
;
72 void TScroller::init(stripfunc
*s
) {
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
);
85 memcpy(&pcScrollData
[iScrollEnd
], pszHead
, iScrollSize
-iScrollEnd
);
86 memcpy(&pcScrollData
[0], pszHead
+ (iScrollSize
-iScrollEnd
),
87 pszTail
-pszHead
-(iScrollSize
-iScrollEnd
));
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;
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
103 // we ought to allocate memory before writing to an address (PB 5/12/98)
105 const LPDWORD lpcWritten
= &cWritten
;
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
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
126 delete [] lpwAttribute
;
130 static void hexify(int x
, char *str
, int len
) {
131 for(int j
= len
- 1; j
>= 0; j
--) {
133 if(str
[j
] > 9) str
[j
] += 'A' - 10;
139 static int setmaxlines(int iDisplay
, int iScrollSize
, int strippedlines
,
142 case HEX
: return(iScrollSize
/ 16); break;
144 case DUMPB
: return(iScrollSize
/ con_width
); break;
145 case TEXTB
: return(strippedlines
); break;
150 static void setstatusline(char *szStatusLine
, int len
, int iDisplay
) {
151 memset(szStatusLine
, ' ', len
);
152 memcpy(&szStatusLine
[1], "Scrollback Mode", 15);
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;
159 memcpy(&szStatusLine
[len
- 6], "READY", 5);
160 szStatusLine
[len
] = 0;
163 void TScroller::ScrollBack(){
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();
172 CHAR_INFO
* chiBuffer
;
173 chiBuffer
= newBuffer();
174 saveScreen(chiBuffer
);
176 HANDLE hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
177 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
178 GetConsoleScreenBufferInfo(hStdout
, &ConsoleInfo
);
180 // Update iScrollBegin -- necessary in case the buffer isn't full yet
181 long iScrollBegin
, iScrollLast
;
184 iScrollLast
= iScrollEnd
- 1;
186 iScrollBegin
= iScrollEnd
;
187 iScrollLast
= iScrollSize
- 1;
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
-
195 if(iScrollBegin
!= 0) memcpy(stripped
+ (iScrollSize
- iScrollBegin
),
196 pcScrollData
, iScrollBegin
- 1);
197 int strippedlines
= (*strip
)(stripped
, stripped
+ iScrollLast
,
200 // Calculate the last line of the scroll buffer (Paul Brannan 12/4/98)
201 int maxlines
= setmaxlines(iDisplay
, iScrollLast
+ 1, strippedlines
,
204 // init scroll position
205 int current
= maxlines
- CON_HEIGHT
+ 1;
206 if(current
< 0) current
= 0;
208 // paint border and info
209 // paint last two lines black on white
211 szStatusLine
= new char[CON_WIDTH
+2];
212 setstatusline(szStatusLine
, CON_COLS
, iDisplay
);
213 WriteConsoleOutputCharAndAttribute(hStdout
, szStatusLine
, status
,
214 CON_LEFT
, CON_BOTTOM
);
216 // loop while not done
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
)
230 p
= pcScrollData
[(c
+16*(r
+current
) + iScrollBegin
) %
232 hexify((char)p
, &szStatusLine
[11 + 3*c
], 2);
234 szStatusLine
[60 + c
] = (char)p
;
236 szStatusLine
[60 + c
] = '.';
239 for(int j
= 0; j
< 16; j
++) {
241 szStatusLine
[CON_COLS
] = '\0';
242 WriteConsoleOutputCharAndAttribute(hStdout
, szStatusLine
,
243 normal
, CON_LEFT
, r
+CON_TOP
);
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
];
255 szStatusLine
[c
] = '.';
257 szStatusLine
[c
] = '\0';
258 WriteConsoleOutputCharAndAttribute(hStdout
, szStatusLine
,
259 normal
, CON_LEFT
, r
+CON_TOP
);
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
];
271 szStatusLine
[c
] = ' ';
273 szStatusLine
[c
] = '\0';
274 WriteConsoleOutputCharAndAttribute(hStdout
, szStatusLine
,
275 normal
, CON_LEFT
, r
+CON_TOP
);
280 // Find the starting position
281 for(ch
= 0, lines
= 0, x
= 1; ch
< iScrollSize
&&
282 lines
< current
; ch
++, x
++) {
284 if(stripped
[ch
] == '\n') lines
++;
285 if(stripped
[ch
] == '\r') x
= 1;
288 for (r
= 0; r
< CON_HEIGHT
; r
++) {
289 memset(szStatusLine
, ' ', CON_COLS
);
290 for(c
= 0; c
<= CON_WIDTH
; c
++) {
292 if (ch
>= iScrollSize
) p
= ' ';
293 else p
= stripped
[ch
];
295 case 10: done
= TRUE
; break;
296 case 13: c
= 0; break;
297 default: szStatusLine
[c
] = p
;
302 szStatusLine
[CON_COLS
] = '\0';
303 WriteConsoleOutputCharAndAttribute(hStdout
, szStatusLine
,
304 normal
, CON_LEFT
, r
+CON_TOP
);
310 setstatusline(szStatusLine
, CON_COLS
, iDisplay
);
311 WriteConsoleOutputCharAndAttribute(hStdout
, szStatusLine
, status
,
312 CON_LEFT
, CON_BOTTOM
);
314 // paint scroll back data
316 switch(scrollkeys()){
321 if ( current
> CON_HEIGHT
)
322 current
-= CON_HEIGHT
;
327 if ( current
< maxlines
- 2*CON_HEIGHT
+ 2)
328 current
+= CON_HEIGHT
;
330 current
= maxlines
- CON_HEIGHT
+ 1;
333 if (current
<= maxlines
- CON_HEIGHT
) current
++;
336 if ( current
> 0) current
--;
339 iDisplay
= (iDisplay
+1)%4;
340 maxlines
= setmaxlines(iDisplay
, iScrollLast
+ 1, strippedlines
,
342 if(current
> maxlines
) current
= maxlines
- 1;
343 if(current
< 0) current
= 0;
346 current
= maxlines
- CON_HEIGHT
+ 1;
347 if(current
< 0) current
= 0;
359 restoreScreen(chiBuffer
);
360 delete[] szStatusLine
;