mirror of
https://github.com/reactos/reactos.git
synced 2026-05-25 08:39:58 +08:00
364 lines
11 KiB
C++
364 lines
11 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
//Telnet Win32 : an ANSI telnet client.
|
|
//Copyright (C) 1998-2000 Paul Brannan
|
|
//Copyright (C) 1998 I.Ioannou
|
|
//Copyright (C) 1997 Brad Johnson
|
|
//
|
|
//This program is free software; you can redistribute it and/or
|
|
//modify it under the terms of the GNU General Public License
|
|
//as published by the Free Software Foundation; either version 2
|
|
//of the License, or (at your option) any later version.
|
|
//
|
|
//This program is distributed in the hope that it will be useful,
|
|
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
//GNU General Public License for more details.
|
|
//
|
|
//You should have received a copy of the GNU General Public License
|
|
//along with this program; if not, write to the Free Software
|
|
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//
|
|
//I.Ioannou
|
|
//roryt@hol.gr
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Module: tscroll.cpp
|
|
//
|
|
// Contents: Telnet Handler
|
|
//
|
|
// Product: telnet
|
|
//
|
|
// Revisions: Dec. 5, 1998 Paul Brannan <pbranna@clemson.edu>
|
|
// June 15, 1998 Paul Brannan
|
|
//
|
|
// This is code originally from tnclass.cpp and ansiprsr.cpp
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "precomp.h"
|
|
|
|
enum {
|
|
HEX,
|
|
DUMP,
|
|
DUMPB,
|
|
TEXTB,
|
|
};
|
|
|
|
int DummyStripBuffer(char *start, char *end, int width) {return 0;}
|
|
|
|
TScroller::TScroller(TMouse &M, int size) : Mouse(M) {
|
|
iScrollSize = size;
|
|
pcScrollData = new char[iScrollSize];
|
|
iScrollEnd = 0;
|
|
iPastEnd = 0;
|
|
memset(pcScrollData, ' ', iScrollSize);
|
|
|
|
if(stricmp(ini.get_scroll_mode(), "hex") == 0) iDisplay = HEX;
|
|
else if(stricmp(ini.get_scroll_mode(), "dump") == 0) iDisplay = DUMP;
|
|
else if(stricmp(ini.get_scroll_mode(), "dumpb") == 0) iDisplay = DUMPB;
|
|
else if(stricmp(ini.get_scroll_mode(), "text") == 0) iDisplay = TEXTB;
|
|
else iDisplay = DUMP;
|
|
|
|
strip = &DummyStripBuffer;
|
|
}
|
|
|
|
TScroller::~TScroller() {
|
|
delete[] pcScrollData;
|
|
}
|
|
|
|
void TScroller::init(stripfunc *s) {
|
|
strip = s;
|
|
}
|
|
|
|
// Fixed update of circular buffer (Paul Brannan 12/4/98)
|
|
// Note: iScrollEnd is one character beyond the end
|
|
void TScroller::update(const char *pszHead, const char *pszTail) {
|
|
if ((iScrollEnd)+(pszTail-pszHead) < iScrollSize) {
|
|
memcpy(&pcScrollData[iScrollEnd], pszHead, pszTail-pszHead);
|
|
} else if (pszTail-pszHead > iScrollSize) {
|
|
memcpy(pcScrollData, pszTail-iScrollSize, iScrollSize);
|
|
iScrollEnd = 0;
|
|
} else {
|
|
memcpy(&pcScrollData[iScrollEnd], pszHead, iScrollSize-iScrollEnd);
|
|
memcpy(&pcScrollData[0], pszHead + (iScrollSize-iScrollEnd),
|
|
pszTail-pszHead-(iScrollSize-iScrollEnd));
|
|
}
|
|
|
|
// This could probably be optimized better, but it's probably not worth it
|
|
int temp = iScrollEnd;
|
|
iScrollEnd = ((iScrollEnd)+(pszTail-pszHead))%iScrollSize;
|
|
if(iScrollEnd < temp) iPastEnd = 1;
|
|
}
|
|
|
|
// Perhaps this should be moved to Tconsole.cpp? (Paul Brannan 6/12/98)
|
|
static BOOL WriteConsoleOutputCharAndAttribute(
|
|
HANDLE hConsoleOutput, // handle of a console screen buffer
|
|
CHAR * lpWriteBuffer,
|
|
WORD wAttrib,
|
|
SHORT sX,
|
|
SHORT sY ){
|
|
// we ought to allocate memory before writing to an address (PB 5/12/98)
|
|
DWORD cWritten;
|
|
const LPDWORD lpcWritten = &cWritten;
|
|
|
|
DWORD cWriteCells = strlen(lpWriteBuffer);
|
|
COORD coordWrite = {sX,sY};
|
|
LPWORD lpwAttribute = new WORD[cWriteCells];
|
|
for (unsigned int i = 0; i < cWriteCells; i++)
|
|
lpwAttribute[i] = wAttrib;
|
|
WriteConsoleOutputAttribute(
|
|
hConsoleOutput, // handle of a console screen buffer
|
|
lpwAttribute, // address of buffer to write attributes from
|
|
cWriteCells, // number of character cells to write to
|
|
coordWrite, // coordinates of first cell to write to
|
|
lpcWritten // address of number of cells written to
|
|
);
|
|
WriteConsoleOutputCharacter(
|
|
hConsoleOutput, // handle of a console screen buffer
|
|
lpWriteBuffer, // address of buffer to write characters from
|
|
cWriteCells, // number of character cells to write to
|
|
coordWrite, // coordinates of first cell to write to
|
|
lpcWritten // address of number of cells written to
|
|
);
|
|
delete [] lpwAttribute;
|
|
return 1;
|
|
}
|
|
|
|
static void hexify(int x, char *str, int len) {
|
|
for(int j = len - 1; j >= 0; j--) {
|
|
str[j] = x % 16;
|
|
if(str[j] > 9) str[j] += 'A' - 10;
|
|
else str[j] += '0';
|
|
x /= 16;
|
|
}
|
|
}
|
|
|
|
static int setmaxlines(int iDisplay, int iScrollSize, int strippedlines,
|
|
int con_width) {
|
|
switch(iDisplay) {
|
|
case HEX: return(iScrollSize / 16); break;
|
|
case DUMP:
|
|
case DUMPB: return(iScrollSize / con_width); break;
|
|
case TEXTB: return(strippedlines); break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void setstatusline(char *szStatusLine, int len, int iDisplay) {
|
|
memset(szStatusLine, ' ', len);
|
|
memcpy(&szStatusLine[1], "Scrollback Mode", 15);
|
|
switch(iDisplay) {
|
|
case HEX: memcpy(&szStatusLine[len / 2 - 1], "HEX", 3); break;
|
|
case DUMP: memcpy(&szStatusLine[len / 2 - 2], "DUMP", 4); break;
|
|
case DUMPB: memcpy(&szStatusLine[len / 2 - 5], "BINARY DUMP", 11); break;
|
|
case TEXTB: memcpy(&szStatusLine[len / 2 - 2], "TEXT", 4); break;
|
|
}
|
|
memcpy(&szStatusLine[len - 6], "READY", 5);
|
|
szStatusLine[len] = 0;
|
|
}
|
|
|
|
void TScroller::ScrollBack(){
|
|
char p;
|
|
int r,c;
|
|
|
|
// define colors (Paul Brannan 7/5/98)
|
|
int normal = (ini.get_scroll_bg() << 4) | ini.get_scroll_fg();
|
|
// int inverse = (ini.get_scroll_fg() << 4) | ini.get_scroll_bg();
|
|
int status = (ini.get_status_bg() << 4) | ini.get_status_fg();
|
|
|
|
CHAR_INFO* chiBuffer;
|
|
chiBuffer = newBuffer();
|
|
saveScreen(chiBuffer);
|
|
|
|
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
|
GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
|
|
|
|
// Update iScrollBegin -- necessary in case the buffer isn't full yet
|
|
long iScrollBegin, iScrollLast;
|
|
if(iPastEnd == 0) {
|
|
iScrollBegin = 0;
|
|
iScrollLast = iScrollEnd - 1;
|
|
} else {
|
|
iScrollBegin = iScrollEnd;
|
|
iScrollLast = iScrollSize - 1;
|
|
}
|
|
|
|
// Create buffer with ANSI codes stripped
|
|
// Fixed this to work properly with a circular buffer (PB 12/4/98)
|
|
char *stripped = new char[iScrollSize];
|
|
memcpy(stripped, pcScrollData + iScrollBegin, iScrollSize -
|
|
iScrollBegin);
|
|
if(iScrollBegin != 0) memcpy(stripped + (iScrollSize - iScrollBegin),
|
|
pcScrollData, iScrollBegin - 1);
|
|
int strippedlines = (*strip)(stripped, stripped + iScrollLast,
|
|
CON_COLS);
|
|
|
|
// Calculate the last line of the scroll buffer (Paul Brannan 12/4/98)
|
|
int maxlines = setmaxlines(iDisplay, iScrollLast + 1, strippedlines,
|
|
CON_COLS);
|
|
|
|
// init scroll position
|
|
int current = maxlines - CON_HEIGHT + 1;
|
|
if(current < 0) current = 0;
|
|
|
|
// paint border and info
|
|
// paint last two lines black on white
|
|
char * szStatusLine;
|
|
szStatusLine = new char[CON_WIDTH+2];
|
|
setstatusline(szStatusLine, CON_COLS, iDisplay);
|
|
WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine, status,
|
|
CON_LEFT, CON_BOTTOM);
|
|
|
|
// loop while not done
|
|
BOOL done = FALSE;
|
|
while (!done){
|
|
switch (iDisplay){
|
|
case HEX:
|
|
memset(szStatusLine, ' ', CON_COLS);
|
|
szStatusLine[8] = ':';
|
|
szStatusLine[34] = '-';
|
|
for (r = 0; r < CON_HEIGHT; r++) {
|
|
hexify((r + current) * 16, &szStatusLine[2], 6);
|
|
for (c = 0; c < 16; c++){
|
|
if (c+(16*(r+current)) >= iScrollLast)
|
|
p = 0;
|
|
else
|
|
p = pcScrollData[(c+16*(r+current) + iScrollBegin) %
|
|
iScrollSize];
|
|
hexify((char)p, &szStatusLine[11 + 3*c], 2);
|
|
if (!iscntrl(p)) {
|
|
szStatusLine[60 + c] = (char)p;
|
|
} else {
|
|
szStatusLine[60 + c] = '.';
|
|
}
|
|
}
|
|
for(int j = 0; j < 16; j++) {
|
|
}
|
|
szStatusLine[CON_COLS] = '\0';
|
|
WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
|
|
normal, CON_LEFT, r+CON_TOP);
|
|
}
|
|
break;
|
|
case DUMP:
|
|
for (r = 0; r < CON_HEIGHT; r++) {
|
|
for (c = 0; c <= CON_WIDTH; c++) {
|
|
if (c+((CON_COLS)*(r+current)) >= iScrollLast) p = ' ';
|
|
else p = pcScrollData[(c+((CON_COLS)*(r+current))
|
|
+ iScrollBegin) % iScrollSize];
|
|
if (!iscntrl(p))
|
|
szStatusLine[c] = p;
|
|
else
|
|
szStatusLine[c] = '.';
|
|
}
|
|
szStatusLine[c] = '\0';
|
|
WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
|
|
normal, CON_LEFT, r+CON_TOP);
|
|
}
|
|
break;
|
|
case DUMPB:
|
|
for (r = 0; r < CON_HEIGHT; r++) {
|
|
for (c = 0; c <= CON_WIDTH; c++) {
|
|
if (c+((CON_COLS)*(r+current)) >= iScrollLast) p = ' ';
|
|
else p = pcScrollData[ (c+((CON_COLS)*(r+current))
|
|
+ iScrollBegin) % iScrollSize];
|
|
if (p != 0)
|
|
szStatusLine[c] = p;
|
|
else
|
|
szStatusLine[c] = ' ';
|
|
}
|
|
szStatusLine[c] = '\0';
|
|
WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
|
|
normal, CON_LEFT, r+CON_TOP);
|
|
}
|
|
break;
|
|
case TEXTB: {
|
|
int ch, lines, x;
|
|
// Find the starting position
|
|
for(ch = 0, lines = 0, x = 1; ch < iScrollSize &&
|
|
lines < current; ch++, x++) {
|
|
|
|
if(stripped[ch] == '\n') lines++;
|
|
if(stripped[ch] == '\r') x = 1;
|
|
}
|
|
|
|
for (r = 0; r < CON_HEIGHT; r++) {
|
|
memset(szStatusLine, ' ', CON_COLS);
|
|
for(c = 0; c <= CON_WIDTH; c++) {
|
|
done = FALSE;
|
|
if (ch >= iScrollSize) p = ' ';
|
|
else p = stripped[ch];
|
|
switch(p) {
|
|
case 10: done = TRUE; break;
|
|
case 13: c = 0; break;
|
|
default: szStatusLine[c] = p;
|
|
}
|
|
ch++;
|
|
if(done) break;
|
|
}
|
|
szStatusLine[CON_COLS] = '\0';
|
|
WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine,
|
|
normal, CON_LEFT, r+CON_TOP);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
setstatusline(szStatusLine, CON_COLS, iDisplay);
|
|
WriteConsoleOutputCharAndAttribute(hStdout, szStatusLine, status,
|
|
CON_LEFT, CON_BOTTOM);
|
|
|
|
// paint scroll back data
|
|
// get key input
|
|
switch(scrollkeys()){
|
|
case VK_ESCAPE:
|
|
done = TRUE;
|
|
break;
|
|
case VK_PRIOR:
|
|
if ( current > CON_HEIGHT)
|
|
current-= CON_HEIGHT;
|
|
else
|
|
current = 0;
|
|
break;
|
|
case VK_NEXT:
|
|
if ( current < maxlines - 2*CON_HEIGHT + 2)
|
|
current += CON_HEIGHT;
|
|
else
|
|
current = maxlines - CON_HEIGHT + 1;
|
|
break;
|
|
case VK_DOWN:
|
|
if (current <= maxlines - CON_HEIGHT) current++;
|
|
break;
|
|
case VK_UP:
|
|
if ( current > 0) current--;
|
|
break;
|
|
case VK_TAB:
|
|
iDisplay = (iDisplay+1)%4;
|
|
maxlines = setmaxlines(iDisplay, iScrollLast + 1, strippedlines,
|
|
CON_COLS);
|
|
if(current > maxlines) current = maxlines - 1;
|
|
if(current < 0) current = 0;
|
|
break;
|
|
case VK_END:
|
|
current = maxlines - CON_HEIGHT + 1;
|
|
if(current < 0) current = 0;
|
|
break;
|
|
case VK_HOME:
|
|
current = 0;
|
|
break;
|
|
case SC_MOUSE:
|
|
Mouse.scrollMouse();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
restoreScreen(chiBuffer);
|
|
delete[] szStatusLine;
|
|
delete[] chiBuffer;
|
|
delete[] stripped;
|
|
}
|