From 7aac59e524e6dc9f1c1faed18340cff7dfd9a47c Mon Sep 17 00:00:00 2001 From: quamrulmina Date: Thu, 15 Oct 2015 17:25:39 -0500 Subject: [PATCH] Add ANSI parsing engine and console draw support to ssh client Makes the ssh.exe client more useable in interactive mode with ANSI color and a console screen support. --- channels.c | 17 +- contrib/win32/win32compat/Makefile.in | 2 +- contrib/win32/win32compat/ansiprsr.c | 922 +++++++++++++ contrib/win32/win32compat/ansiprsr.h | 46 + contrib/win32/win32compat/console.c | 1764 +++++++++++++++++++++++++ contrib/win32/win32compat/console.h | 114 ++ contrib/win32/win32compat/tncon.h | 158 +++ contrib/win32/win32compat/tnnet.c | 74 ++ contrib/win32/win32compat/tnnet.h | 24 + ssh.c | 1 + 10 files changed, 3108 insertions(+), 14 deletions(-) create mode 100644 contrib/win32/win32compat/ansiprsr.c create mode 100644 contrib/win32/win32compat/ansiprsr.h create mode 100644 contrib/win32/win32compat/console.c create mode 100644 contrib/win32/win32compat/console.h create mode 100644 contrib/win32/win32compat/tncon.h create mode 100644 contrib/win32/win32compat/tnnet.c create mode 100644 contrib/win32/win32compat/tnnet.h diff --git a/channels.c b/channels.c index f5c3e8d..1dd0777 100644 --- a/channels.c +++ b/channels.c @@ -2454,25 +2454,16 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) c->local_window -= win_len; } - #ifdef WIN32_FIXME - if ( (c->client_tty) && (data_len >= 5) ) { - if ( data[0] == '\033' ) { // escape char octal 33, decimal 27 - if ( (data[1] == '[') && (data[2]== '2') && (data[3]== '0') && ( data[4]== 'h' )) { - lftocrlf = 1; - data = data + 5 ; // we have processed the 5 bytes ESC sequence - data_len = data_len - 5; - } - } - } - #endif - if (c->datagram) buffer_put_string(&c->output, data, data_len); else { #ifndef WIN32_FIXME buffer_append(&c->output, data, data_len); #else - buffer_append(&c->output, data, data_len); + if ( c->client_tty ) + telProcessNetwork ( data, data_len ); // run it by ANSI engine if it is the ssh client + else + buffer_append(&c->output, data, data_len); // it is the sshd server, so pass it on if ( c->isatty ) { buffer_append(&c->input, data, data_len); // we echo the data if it is sshd server and pty interactive mode if ( (data_len ==1) && (data[0] == '\b') ) diff --git a/contrib/win32/win32compat/Makefile.in b/contrib/win32/win32compat/Makefile.in index 027f868..3be0243 100644 --- a/contrib/win32/win32compat/Makefile.in +++ b/contrib/win32/win32compat/Makefile.in @@ -18,7 +18,7 @@ LDFLAGS=-L. @LDFLAGS@ WIN32COMPATFILES = daemon.o gettimeofday.o homedirhelp.o pwd.o sfds.o \ socket.o startupneeds.o strcasecmp.o syslog.o lsalogon.o lsastring.o \ - stringhelp.o deskright.o win32auth.o kerberos.o + stringhelp.o deskright.o win32auth.o kerberos.o ansiprsr.o console.o tnnet.o WIN32COMPATLIB=@LIBWIN32COMPAT@ diff --git a/contrib/win32/win32compat/ansiprsr.c b/contrib/win32/win32compat/ansiprsr.c new file mode 100644 index 0000000..c3d5631 --- /dev/null +++ b/contrib/win32/win32compat/ansiprsr.c @@ -0,0 +1,922 @@ +/* ansiprsr.c + * Author: Pragma Systems, Inc. + * Contribution by Pragma Systems, Inc. for Microsoft openssh win32 port + * Copyright (c) 2011, 2015 Pragma Systems, Inc. + * All rights reserved + * + * ANSI Parser to run on Win32 based operating systems. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice. + * 2. Binaries produced provide no direct or implied warranties or any + * guarantee of performance or suitability. + */ + +#include +#include +#include +#include + +#include +#include + +#include "ansiprsr.h" +#include "tncon.h" +#include "tnnet.h" + +#define TS_IS 0 +#define TS_SEND 1 + +// items used from other modules +int NetWriteString(char* pszString, size_t cbString); +TelParams Parameters; +extern int lftocrlf; + +extern int ScreenX; +extern int ScreenY; +extern int ScrollTop; +extern int ScrollBottom; +// end of imports from outside module + +bool gbVTAppMode = false; + +// private message for port printing to +unsigned char VT_ST[] = { 0x1b, '/', '\0' }; + +static int AutoWrap = 1; + +int marginTop, marginBottom; +BOOL bAtEOLN = FALSE; + +static int term_mode; + +// ParseANSI globals - these need to be here, because sometimes blocks are sent +// in mid ANSI sequence +int iParam[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int iCurrentParam = 0; +int bDelimiter = 0; +int bMode = 0; +int fcompletion = 1; +int bExtMode = 0; +int bCS0 = 0; +int bCS1 = 0; +int bBkMode = 0; +int bCharMode = 0; + + +BOOL fShiftOut = FALSE; +BOOL InPrintMode = FALSE; +BOOL fPcMode = FALSE; + +char printErr[] = "Unable to Print: Printer not assigned. Press any key to continue..."; + +#define MODE_CURSORAPP 0x0001 +#define MODE_ANSIVT52 0x0002 +#define MODE_COL132 0x0004 +#define MODE_SMOOTHSCROLL 0x0008 +#define MODE_REVERSESCREEN 0x0010 +#define MODE_ORIGINREL 0x0020 +#define MODE_WRAPAROUND 0x0040 +#define MODE_AUTOREPEAT 0x0080 +#define MODE_APPMODE 0x0100 +#define MODE_LNM 0x0200 +#define MODE_IRM_INSERT 0x0400 + +int VTMode = 0; + +#define MODE_CURSORAPP 0x0001 +#define MODE_ANSIVT52 0x0002 +#define MODE_COL132 0x0004 +#define MODE_SMOOTHSCROLL 0x0008 +#define MODE_REVERSESCREEN 0x0010 +#define MODE_ORIGINREL 0x0020 +#define MODE_WRAPAROUND 0x0040 +#define MODE_AUTOREPEAT 0x0080 +#define MODE_APPMODE 0x0100 +#define MODE_LNM 0x0200 + +char *GetTerminalId() +{ + return "\033[?1;2c"; +} + +char * GetStatusReport() +{ + return "\033[2;5R"; +} + +void BufConvertToG2(char * pszBuffer, int length) +{ + int i; + + for (i=0;i= (ConWindowSizeY()-1)) + { + ConScrollDown(ScrollTop,ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + ConMoveCursorPosition(-ConGetCursorX(),1); + bAtEOLN = FALSE; +} + +unsigned char* ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd) +{ + int CurrentX; + int CurrentY; + int rc = 0, bufLen, cmpLen, i; + + + if (!fcompletion) + { + if (pszBuffer < pszBufferEnd -1) + { + unsigned char * pszCurrent = pszBuffer+1; + unsigned char * pszNewCurrent = pszCurrent; + + if (term_mode == TERM_ANSI) + { + pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd); + } + else if (term_mode == TERM_VT52) + { + pszNewCurrent = ParseVT52(pszCurrent, pszBufferEnd); + } + if ( pszCurrent == pszNewCurrent ) // didn't move inside Parsefunction + { + pszNewCurrent += ConWriteString( (char *)pszCurrent, 1); + return pszBuffer + 1; + } + if (pszNewCurrent > pszCurrent ) + pszBuffer = pszNewCurrent; + } + } + switch ((unsigned char) (*pszBuffer)) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 11: + pszBuffer++; + break; + + case 7: + Beep( 1000, 400); + pszBuffer++; + break; + + case 8: + pszBuffer++; + if (!bAtEOLN) + { + CurrentX = ConGetCursorX(); + if (CurrentX == 0) + { + ConMoveCursorPosition( ScreenX-1,-1); + ConWriteString(" ",1); + // ConMoveCursorPosition(-1,0); + } + else + { + ConClearNFromCursorLeft(1); + ConMoveCursorPosition( -1, 0 ); + } + } + bAtEOLN = FALSE; + + //ConWriteString( " ", 1 ); + //ConMoveCursorPosition( -1, 0 ); + break; + + case 9: + { + if (bAtEOLN) GoToNextLine(); + int i, MoveRight = 8 - (ConGetCursorX() % 8); + + for ( i = 0; i < MoveRight; i++ ) + ConWriteString( " ", 1 ); + pszBuffer++; + AutoWrap = 1; + bAtEOLN = FALSE; + } + break; + + case 10: + + + pszBuffer++; + CurrentY = ConGetCursorY(); + + + if (CurrentY >= marginBottom ) + { + if (VTMode & MODE_APPMODE) + ConScrollDown(marginTop,marginBottom); + else + printf("\n"); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + { + ConMoveCursorPosition(0,1); + } + if ( Parameters.nReceiveCRLF == ENUM_LF ) + ConMoveCursorPosition(-ConGetCursorX(),0); + AutoWrap = 1; + bAtEOLN = FALSE; + break; + + case 12: + pszBuffer++; + ConSetCursorPosition(0, 0); + ConClearScreen(); + AutoWrap = 1; + bAtEOLN = FALSE; + break; + + case 13: + pszBuffer++; + ConMoveCursorPosition(-ConGetCursorX(),0); + AutoWrap = 1; + bAtEOLN = FALSE; + break; + + case 14: + pszBuffer++; + fShiftOut = TRUE; + break; + + case 15: + fShiftOut = FALSE; + pszBuffer++; + break; + + case 27: + if (pszBuffer < pszBufferEnd -1) + { + unsigned char * pszCurrent = pszBuffer+1; + unsigned char * pszNewCurrent = pszCurrent; + + if ( *pszCurrent == 27 ) + { + pszNewCurrent += ConWriteString( (char *)pszCurrent, 1); + return pszBuffer + 1; + } + else + { + if (term_mode == TERM_ANSI) + { + pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd); + } + else if (term_mode == TERM_VT52) + { + pszNewCurrent = ParseVT52(pszCurrent, pszBufferEnd); + } + } + if (pszNewCurrent > pszCurrent ) + pszBuffer = pszNewCurrent; + } + break; + + default: + { + if (bAtEOLN) GoToNextLine(); + + unsigned char* pszCurrent = pszBuffer; + CurrentX = ConGetCursorX(); + + while ((pszCurrent < pszBufferEnd) && (*pszCurrent != (unsigned char)27) + && (*pszCurrent > (unsigned char)15) && (*pszCurrent != (unsigned char)255) + && (CurrentX++ < ScreenX )) + // (*pszCurrent != (char)15) && (*pszCurrent != (char)14) && + // (*pszCurrent != (char)12) && (*pszCurrent != (char)13) && (*pszCurrent != (char)8) && + // (*pszCurrent != (char)9)) + pszCurrent++; + + if (fShiftOut) + memset( pszBuffer, '|', pszCurrent-pszBuffer ); + + pszBuffer += ConWriteString((char *)pszBuffer, (int)(pszCurrent - pszBuffer)); + + if ((CurrentX >= ScreenX) && AutoWrap && !(VTMode & MODE_CURSORAPP) ) + { + bAtEOLN = TRUE; + } + + break; + } + } + + return pszBuffer; +} + + +unsigned char * GetNextChar(unsigned char * pszBuffer, unsigned char *pszBufferEnd) +{ + if (++pszBuffer > pszBufferEnd) + return NULL; + else + return pszBuffer; +} + +void ConSetExtendedMode(int iFunction, BOOL bEnable) +{ + switch(iFunction) + { + case 1: + if (bEnable){ + VTMode |= MODE_CURSORAPP; + gbVTAppMode = true; + }else{ + VTMode &= ~MODE_CURSORAPP; + gbVTAppMode = false; + } + break; + case 2: + if (!bEnable) + VTMode |= MODE_ANSIVT52; + break; + case 3: + if (bEnable) + VTMode |= MODE_COL132; + else + VTMode &= ~MODE_COL132; + break; + case 4: + if (bEnable) + VTMode |= MODE_SMOOTHSCROLL; + else + VTMode &= ~MODE_SMOOTHSCROLL; + break; + case 5: + if (bEnable) + VTMode |= MODE_REVERSESCREEN; + else + VTMode &= ~MODE_REVERSESCREEN; + break; + case 6: + if (bEnable) + VTMode |= MODE_ORIGINREL; + else + VTMode &= ~MODE_ORIGINREL; + break; + case 7: + if (bEnable) + VTMode |= MODE_WRAPAROUND; + else + VTMode &= ~MODE_WRAPAROUND; + break; + case 8: + if (bEnable) + VTMode |= MODE_AUTOREPEAT; + else + VTMode &= ~MODE_AUTOREPEAT; + break; + case 20: // LNM Mode CSI 20h + if (bEnable){ + VTMode |= MODE_LNM; + Parameters.nReceiveCRLF = ENUM_LF; + lftocrlf = 1; + }else{ + VTMode &= ~MODE_LNM; + Parameters.nReceiveCRLF = ENUM_CRLF; + lftocrlf = 0; + } + break; + case 25: + ConDisplayCursor(bEnable); + break; + + } + + if ((iFunction == 2) && (bEnable)) + { + term_mode = TERM_VT52; + } +} + +#define MODE_EXT 0x00000001 +#define MODE_CS0 0x00000002 +#define MODE_CS1 0x00000004 +#define MODE_CS2 0x00000008 +#define MODE_CS3 0x00000010 +#define MODE_BRK 0x00000020 +#define MODE_CHAR 0x00000040 +#define MODE_K 0x00000080 + +#define DIGI_MASK (MODE_CS0 | MODE_CS1 | MODE_CS2 | MODE_CS3 | MODE_CHAR) + +unsigned char * ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd) +{ + unsigned char * pszCurrent = pszBuffer; + const int nParam = 10; // Maximum number of parameters + int rc = 0; + static int SavedX = 0; + static int SavedY = 0; + SCREEN_HANDLE hScreen = NULL; + char anyKey[2] = " "; + WORD BytesRead; + char pszServerPort[10]; + int indx; + char jobName[40]; + + fcompletion = 0; + do + { + switch ((unsigned char) *pszCurrent) + { + case ';': // delimiter + bDelimiter = TRUE; + break; +// Modifiers + case '?': // Extended Mode + bMode |= MODE_EXT; + break; + case '(': + bMode |= MODE_CS0; + break; + case ')': + bMode |= MODE_CS1; + break; + case '*': + bMode |= MODE_CS2; + break; + case '+': + bMode |= MODE_CS3; + break; + case '[': + bMode |= MODE_BRK; + break; + case '#': + bMode |= MODE_CHAR; + break; + +// Termination Options + case 0: + fcompletion = 1; + break; + + case '}': + fcompletion = 1; + break; + + case '<': // character set + fcompletion = 1; + break; + + case '\\': + fcompletion = 1; + break; + + case '~': + fcompletion = 1; + break; + case '^': // private message pszCurrent++; + while (_strnicmp((const char *)pszCurrent, (const char *)VT_ST, strlen((const char *)VT_ST) ) )// while not stop + { + if (_strnicmp((const char *)pszCurrent, (const char *)VT_ST, strlen((const char *)VT_ST) ) ) + pszCurrent++; + } + pszCurrent += strlen((const char *)VT_ST) - 1; + fcompletion = 1; + break; + + case 'A': // British Character Set or Cursor Up + if (bMode & MODE_CHAR) + { + // Britsh Character Set + } + else if (bMode & MODE_BRK) + { + // Cursor UP + if (iCurrentParam < 1) + iParam[0] = 1; + ConMoveCursorPosition(0, -iParam[0]); +// AutoWrap = 0; + } + fcompletion = 1; + break; + case 'B': // US ASCII or Cursor down + if (bMode & MODE_CHAR) + { + // US ASCII Character Set + } + else if (bMode & MODE_BRK) + { + // Cursor DOWN + if (iCurrentParam < 1) + iParam[0] = 1; + ConMoveCursorPosition(0, iParam[0]); +// AutoWrap = 0; + } + fcompletion = 1; + break; + case 'C': // Finish Character Set or Cursor right + if (bMode & MODE_CHAR) + { + // Britsh Character Set + } + else if (bMode & MODE_BRK) + { + // Cursor right + if (iCurrentParam < 1) + iParam[0] = 1; + ConMoveCursorPosition(iParam[0], 0); +// AutoWrap = 0; + } + fcompletion = 1; + break; + case 'D': // Cursor left + if (bMode & MODE_BRK) + { + // Cursor left + if (iCurrentParam < 1) + iParam[0] = 1; + ConMoveCursorPosition(-iParam[0], 0); +// AutoWrap = 0; + } + else if (bMode == 0) + { + // Index + ConScrollDown(ScrollTop,ScrollBottom); + } + fcompletion = 1; + bAtEOLN = FALSE; + break; + + + case '=': // application mode + VTMode |= MODE_APPMODE; + fcompletion = 1; + break; + case '>': // numeric mode + VTMode &= ~MODE_APPMODE; + fcompletion = 1; + break; + + case '%': // character set definitions + + fcompletion = 1; + break; + case 'h': + case 'l': // ^[?25h + if (bMode & MODE_EXT) + { + if (iParam[0] == 4){ + VTMode |= MODE_IRM_INSERT; + } +// iParam[0] = atoi( (pszCurrent - iCurrentParam) ); + int i; + for ( i = 0; i < iCurrentParam; i++ ) + ConSetExtendedMode(iParam[i], *pszCurrent=='h'?1:0); + } + else if (bMode & MODE_BRK) + { + // Possible set Line feed (option 20) + // Possible set Line feed (option 20) + if (iParam[0] == 20) + ConSetExtendedMode(iParam[0], *pszCurrent=='h'?1:0); + if (iParam[0] == 4){ + VTMode &= ~MODE_IRM_INSERT; + } + } + fcompletion = 1; + break; + + case 'L': + if (iParam[0]) + { + int i; + for (i=0; i 0) ? iParam[0] - 1 : 0; + marginBottom = (iParam[1] > 0) ? iParam[1] - 1 : 0; + + fcompletion = 1; + break; + case 'H': + case 'f': + if (bMode & MODE_BRK) + { + if ((iParam[0]-1) > ConWindowSizeY()) + ConSetScreenRect(ConWindowSizeX(), iParam[0]-1); + ConSetCursorPosition((iParam[1] > 0) ? iParam[1] - 1 : 0, (iParam[0] > 0) ? iParam[0] - 1 : 0); + //AutoWrap = 0; + } + else if (bMode == 0) + { + //Set tab + } + fcompletion = 1; + bAtEOLN = FALSE; + break; + + case 'M': + if (iParam[0]) + { + int i ; + for (i=0; i': // Exit Alt Keypad mode + case '1': // Graphics processor on + case '2': // Graphics processor off + pszCurrent++; + break; + case '<': // Enter ANSI mode + term_mode = TERM_ANSI; + pszCurrent++; + break; + default: + pszCurrent++; + } + + return pszCurrent; + +} diff --git a/contrib/win32/win32compat/ansiprsr.h b/contrib/win32/win32compat/ansiprsr.h new file mode 100644 index 0000000..96e1159 --- /dev/null +++ b/contrib/win32/win32compat/ansiprsr.h @@ -0,0 +1,46 @@ +/* ansiprsr.h + * Author: Pragma Systems, Inc. + * Contribution by Pragma Systems, Inc. for Microsoft openssh win32 port + * Copyright (c) 2011, 2015 Pragma Systems, Inc. + * All rights reserved + * + * ANSI Parser header file to run on Win32 based operating systems. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice. + * 2. Binaries produced provide no direct or implied warranties or any + * guarantee of performance or suitability. + */ + +#ifndef __ANSIPRSR_H +#define __ANSIPRSR_H + +#define TERM_ANSI 0 +#define TERM_VT52 1 + +unsigned char * ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd); +unsigned char * GetNextChar(unsigned char * pszBuffer, unsigned char *pszBufferEnd); +unsigned char * ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd); +unsigned char * ParseVT52(unsigned char * pszBuffer, unsigned char * pszBufferEnd); + +#define true TRUE +#define false FALSE +#define bool BOOL + +//typedef enum _crlftype { CRLF = 0, LF, CR } CRLFType; +#define ENUM_CRLF 0 +#define ENUM_LF 1 +#define ENUM_CR 2 + +typedef struct _TelParams +{ + int timeOut; + int fLocalEcho; + int fTreatLFasCRLF; + int fSendCROnly; + int nReceiveCRLF; +} TelParams; + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/console.c b/contrib/win32/win32compat/console.c new file mode 100644 index 0000000..4ed1b8b --- /dev/null +++ b/contrib/win32/win32compat/console.c @@ -0,0 +1,1764 @@ +/* console.c + * Author: Pragma Systems, Inc. + * Contribution by Pragma Systems, Inc. for Microsoft openssh win32 port + * Copyright (c) 2011, 2015 Pragma Systems, Inc. + * All rights reserved + * + * Common library for Windows Console Screen IO. + * Contains Windows console related definition so that emulation code can draw + * on Windows console screen surface. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice. + * 2. Binaries produced provide no direct or implied warranties or any + * guarantee of performance or suitability. + */ + +#include +#include +#include + +#include + +#include +#include + +HANDLE hConsole = NULL; +DWORD dwSavedAttributes = 0; + +WORD wStartingAttributes = 0; + +int ScreenX; +int ScreenY; +int ScrollTop; +int ScrollBottom; + +char *pSavedScreen = NULL; +static COORD ZeroCoord = {0,0}; +COORD SavedScreenSize = {0,0}; +COORD SavedScreenCursor = {0, 0 }; +SMALL_RECT SavedViewRect = {0,0,0,0}; + +typedef struct _SCREEN_RECORD{ + PCHAR_INFO pScreenBuf; + COORD ScreenSize; + COORD ScreenCursor; + SMALL_RECT srWindowRect; +}SCREEN_RECORD,*PSCREEN_RECORD; + +PSCREEN_RECORD pSavedScreenRec = NULL; + + +/* ************************************************************ */ +/* Function: ConInit */ +/* Used to Initialize the Console for output */ +/* ************************************************************ */ +int ConInit( DWORD OutputHandle, bool fSmartInit ) +{ + + OSVERSIONINFO os; + DWORD dwAttributes = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + static bool bFirstConInit = true; + + os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + GetVersionEx( &os ); + + hConsole = GetStdHandle( OutputHandle ); + if (hConsole == INVALID_HANDLE_VALUE) + printf("GetStdHandle failed with %d\n",GetLastError()); + + if (!GetConsoleMode( hConsole, &dwSavedAttributes )) + printf("GetConsoleMode failed with %d\n",GetLastError()); + + dwAttributes = dwSavedAttributes; + + if ( os.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { +// dwAttributes = (DWORD)ENABLE_WRAP_AT_EOL_OUTPUT; // Causes screen scroll in Edit +// dwAttributes = (DWORD)(ENABLE_PROCESSED_OUTPUT & ~(ENABLE_WRAP_AT_EOL_OUTPUT)); +// dwAttributes = 0; // Causes wrong FONTS and doesn't handle CRLF + dwAttributes = (DWORD)ENABLE_PROCESSED_OUTPUT; // PERFECT in NT +// dwAttributes = (DWORD)ENABLE_PROCESSED_OUTPUT | (DWORD)ENABLE_WRAP_AT_EOL_OUTPUT; // PERFECT in NT + SetConsoleMode(hConsole, dwAttributes ); // Windows NT + } + else + { + dwAttributes = (DWORD)ENABLE_WRAP_AT_EOL_OUTPUT; // Doesn't always print last column & doesn't handle CRLF +// dwAttributes = (DWORD)(ENABLE_PROCESSED_OUTPUT & ~(ENABLE_WRAP_AT_EOL_OUTPUT)); +// dwAttributes = 0; // Causes wrong FONTS and doesn't handle CRLF +// dwAttributes = (DWORD)ENABLE_PROCESSED_OUTPUT; // Scrolls in Windows 95 + SetConsoleMode(hConsole, dwAttributes ); // Windows 95 + } + + + + + if (bFirstConInit && fSmartInit) + { + + if (GetConsoleScreenBufferInfo(hConsole, &csbi)) + { + SMALL_RECT sr; + + wStartingAttributes = csbi.wAttributes; + + int ydelta = csbi.srWindow.Bottom-csbi.srWindow.Top+1; + if (csbi.dwCursorPosition.Y+ydelta > csbi.dwSize.Y) + { + // not enough buffer to reposition window.. must scroll + SMALL_RECT ScrollRect; + SMALL_RECT ClipRect; + COORD destination; + CHAR_INFO Fill; + COORD newCursorPos; + + ScrollRect.Top = (csbi.dwCursorPosition.Y+ydelta - csbi.dwSize.Y); + ScrollRect.Bottom = csbi.dwCursorPosition.Y+1; + ScrollRect.Left = 0; + ScrollRect.Right = csbi.dwSize.X; + + ClipRect = ScrollRect; + ClipRect.Top = 0; + + destination.X = 0; + destination.Y = 0; + + Fill.Attributes = csbi.wAttributes; + Fill.Char.AsciiChar = ' '; + + + ScrollConsoleScreenBuffer( hConsole, + &ScrollRect, + &ClipRect, + destination, + &Fill + ); + + + + + newCursorPos.Y = csbi.dwSize.Y-ydelta; + + + newCursorPos.X = csbi.dwCursorPosition.X; + SetConsoleCursorPosition(hConsole,newCursorPos); + + sr = csbi.srWindow; + sr.Top = newCursorPos.Y; + sr.Bottom = csbi.dwSize.Y-1; + + + BOOL rc = SetConsoleWindowInfo(hConsole,TRUE,&sr); + + + }else{ + GetConsoleScreenBufferInfo(hConsole, &csbi); + + sr = csbi.srWindow; + sr.Top = csbi.dwCursorPosition.Y; + sr.Bottom = sr.Top+ydelta-1; + + + BOOL rc = SetConsoleWindowInfo(hConsole,TRUE,&sr); + } + + } + bFirstConInit = false; + } + + ConSetScreenX(); + ConSetScreenY(); + ScrollTop = 0; + ScrollBottom = ConWindowSizeY(); + + if (GetConsoleScreenBufferInfo(hConsole, &csbi)) + SavedViewRect = csbi.srWindow; + + return 0; +} + + +/* ************************************************************ */ +/* Function: ConUnInit */ +/* Used to Uninitialize the Console */ +/* ************************************************************ */ +int ConUnInit( void ) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if ( hConsole == NULL ) + return 0; + + + + if (!GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo)) + return 0; + + SetConsoleMode(hConsole,dwSavedAttributes); + + + return 0; +} + +/* ************************************************************ */ +/* Function: ConUnInit */ +/* Used to Uninitialize the Console */ +/* ************************************************************ */ +int ConUnInitWithRestore( void ) +{ + DWORD dwWritten; + COORD Coord ; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if ( hConsole == NULL ) + return 0; + + + + if (!GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo)) + return 0; + + SetConsoleMode(hConsole,dwSavedAttributes); + + Coord = ConsoleInfo.dwCursorPosition; + Coord.X = 0; + + DWORD dwNumChar = (ConsoleInfo.dwSize.Y - ConsoleInfo.dwCursorPosition.Y) * + ConsoleInfo.dwSize.X; + + FillConsoleOutputCharacter(hConsole, ' ', + dwNumChar, + Coord, &dwWritten); + FillConsoleOutputAttribute(hConsole, wStartingAttributes, + dwNumChar, + Coord, &dwWritten); + + SetConsoleTextAttribute( hConsole, wStartingAttributes ); + + return 0; +} + +// BLR - rewrite of ConSetScreenSize that doesn't alter buffer size + +BOOL ConSetScreenRect( int xSize, int ySize ) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ + BOOL bSuccess = TRUE; + SMALL_RECT srWindowRect; /* hold the new console size */ + COORD coordScreen; + + bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); + + /* get the largest size we can size the console window to */ + coordScreen = GetLargestConsoleWindowSize(hConsole); + + /* define the new console window size and scroll position */ + srWindowRect.Top = csbi.srWindow.Top; + srWindowRect.Left = csbi.srWindow.Left; + srWindowRect.Right = xSize - 1 + srWindowRect.Left; + srWindowRect.Bottom = ySize - 1 + srWindowRect.Top; + + /* define the new console buffer size */ + coordScreen.X = max(csbi.dwSize.X, xSize); + coordScreen.Y = max(csbi.dwSize.Y, ySize); + + /* if the current buffer is larger than what we want, resize the */ + /* console window first, then the buffer */ + if (csbi.dwSize.X < coordScreen.X || + csbi.dwSize.Y < coordScreen.Y) + { + bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); + if (bSuccess) + bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); + } + else + { + bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); + if (bSuccess) + bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); + } + + if (bSuccess) + ConSaveViewRect(); + + /* if the current buffer *is* the size we want, don't do anything! */ + return bSuccess; +} + +BOOL ConSetScreenSize( int xSize, int ySize ) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ + BOOL bSuccess = TRUE; + SMALL_RECT srWindowRect; /* hold the new console size */ + COORD coordScreen; + + bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); + + /* get the largest size we can size the console window to */ + coordScreen = GetLargestConsoleWindowSize(hConsole); + + /* define the new console window size and scroll position */ + srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1); + srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1); + srWindowRect.Left = srWindowRect.Top = (SHORT) 0; + + /* define the new console buffer size */ + coordScreen.X = xSize; + coordScreen.Y = ySize; + + /* if the current buffer is larger than what we want, resize the */ + /* console window first, then the buffer */ + if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) xSize * ySize) + { + bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); + if (bSuccess) + { + bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); + } + } + + /* if the current buffer is smaller than what we want, resize the */ + /* buffer first, then the console window */ + if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) xSize * ySize) + { + bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); + if (bSuccess) + bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); + } + + if (bSuccess) + ConSaveViewRect(); + + /* if the current buffer *is* the size we want, don't do anything! */ + return bSuccess; +} + +/* ************************************************************ */ +/* Function: ConRedrawScreen */ +/* Redraws the saved screen */ +/* ************************************************************ */ +DWORD ConRedrawScreen( void ) +{ + PCHAR_INFO pInfo; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + int i; + + if ( pSavedScreen == NULL ) + return 1; + + if (!GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo)) + return 1; + + pInfo = (PCHAR_INFO)pSavedScreen; + + for ( i = 0; i < (ConsoleInfo.dwSize.X * ConsoleInfo.dwSize.Y); i++ ) + { + pInfo++; + } + return 0; +} + +bool fFirstTime = true; +/* ************************************************************ */ +/* Function: ConSetAttributes */ +/* Used to set the Color of the console and other attributes */ +/* 6/21/99 BLH commented out INTENSITY FLAGS for cyan, magenta, and yellow */ +/* it appears that they weren't commented out when the check for intensity + was added - since i'm not sure why we would explicitly state high + intensity for those colors +/* ************************************************************ */ +void ConSetAttribute( int *iParam, int iParamCount ) +{ + int iAttr; + int i; + + iAttr = 0; + if (iParamCount < 1) + SetConsoleTextAttribute(hConsole,FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + else + { + for (i=0;i