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 } 364