summaryrefslogtreecommitdiff
path: root/dedicated/console
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /dedicated/console
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'dedicated/console')
-rw-r--r--dedicated/console/TextConsoleUnix.cpp419
-rw-r--r--dedicated/console/TextConsoleUnix.h44
-rw-r--r--dedicated/console/TextConsoleWin32.cpp644
-rw-r--r--dedicated/console/TextConsoleWin32.h82
-rw-r--r--dedicated/console/conproc.cpp428
-rw-r--r--dedicated/console/conproc.h30
-rw-r--r--dedicated/console/textconsole.cpp22
-rw-r--r--dedicated/console/textconsole.h38
8 files changed, 1707 insertions, 0 deletions
diff --git a/dedicated/console/TextConsoleUnix.cpp b/dedicated/console/TextConsoleUnix.cpp
new file mode 100644
index 0000000..4f71845
--- /dev/null
+++ b/dedicated/console/TextConsoleUnix.cpp
@@ -0,0 +1,419 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// CTextConsoleUnix.cpp: Unix implementation of the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef _WIN32
+
+#include <sys/ioctl.h>
+
+#include "TextConsoleUnix.h"
+#include "tier0/icommandline.h"
+#include "tier1/utllinkedlist.h"
+#include "filesystem.h"
+#include "../thirdparty/libedit-3.1/src/histedit.h"
+#include "tier0/vprof.h"
+
+#define CONSOLE_LOG_FILE "console.log"
+
+static pthread_mutex_t g_lock;
+static pthread_t g_threadid = (pthread_t)-1;
+CUtlLinkedList< CUtlString > g_Commands;
+static volatile int g_ProcessingCommands = false;
+
+#if defined( LINUX )
+
+// Dynamically load the libtinfo stuff. On servers without a tty attached,
+// we get to skip all of these dependencies on servers without ttys.
+#define TINFO_SYM(rc, fn, params, args, ret) \
+ typedef rc (*DYNTINFOFN_##fn) params; \
+ static DYNTINFOFN_##fn g_TINFO_##fn; \
+ extern "C" rc fn params \
+ { \
+ ret g_TINFO_##fn args; \
+ }
+
+TINFO_SYM(char *, tgoto, (char *string, int x, int y), (string, x, y), return);
+TINFO_SYM(int, tputs, (const char *str, int affcnt, int (*putc)(int)), (str, affcnt, putc), return);
+TINFO_SYM(int, tgetflag, (char *id), (id), return);
+TINFO_SYM(int, tgetnum, (char *id), (id), return);
+TINFO_SYM(int, tgetent, (char *bufp, const char *name), (bufp, name), return);
+TINFO_SYM(char *, tgetstr, (char *id, char **area), (id, area), return);
+
+#endif // LINUX
+
+//----------------------------------------------------------------------------------------------------------------------
+// init_tinfo_functions
+//----------------------------------------------------------------------------------------------------------------------
+static bool init_tinfo_functions()
+{
+#if !defined( LINUX )
+ return true;
+#else
+ static void *s_ncurses_handle = NULL;
+
+ if ( !s_ncurses_handle )
+ {
+ // Long time ago, ncurses was two libraries. So if libtinfo fails, try libncurses.
+ static const char *names[] = { "libtinfo.so.5", "libncurses.so.5" };
+
+ for ( int i = 0; !s_ncurses_handle && ( i < ARRAYSIZE( names ) ); i++ )
+ {
+ bool bFailed = true;
+ s_ncurses_handle = dlopen( names[i], RTLD_NOW );
+
+ if ( s_ncurses_handle )
+ {
+ bFailed = false;
+#define LOADTINFOFUNC(_handle, _func, _failed) \
+ do { \
+ g_TINFO_##_func = ( DYNTINFOFN_##_func )dlsym(_handle, #_func); \
+ if ( !g_TINFO_##_func) \
+ _failed = true; \
+ } while (0)
+
+ LOADTINFOFUNC( s_ncurses_handle, tgoto, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tputs, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetflag, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetnum, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetent, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetstr, bFailed );
+#undef LOADTINFOFUNC
+ }
+
+ if ( bFailed )
+ s_ncurses_handle = NULL;
+ }
+
+ if ( !s_ncurses_handle )
+ {
+ fprintf( stderr, "\nWARNING: Failed to load 32-bit libtinfo.so.5 or libncurses.so.5.\n"
+ " Please install (lib32tinfo5 / ncurses-libs.i686 / equivalent) to enable readline.\n\n");
+ }
+ }
+
+ return !!s_ncurses_handle;
+#endif // LINUX
+}
+
+static unsigned char editline_complete( EditLine *el, int ch __attribute__((__unused__)) )
+{
+ static const char *s_cmds[] =
+ {
+ "cvarlist ",
+ "find ",
+ "help ",
+ "maps ",
+ "nextlevel",
+ "quit",
+ "status",
+ "sv_cheats ",
+ "tf_bot_quota ",
+ "toggle ",
+ "sv_dump_edicts",
+#ifdef STAGING_ONLY
+ "tf_bot_use_items ",
+#endif
+ };
+
+ const LineInfo *lf = el_line(el);
+ const char *cmd = lf->buffer;
+ size_t len = lf->cursor - cmd;
+
+ if ( len > 0 )
+ {
+ for (int i = 0; i < ARRAYSIZE(s_cmds); i++)
+ {
+ if ( len > strlen( s_cmds[i] ) )
+ continue;
+
+ if ( !Q_strncmp( cmd, s_cmds[i], len ) )
+ {
+ if ( el_insertstr( el, s_cmds[i] + len ) == -1 )
+ return CC_ERROR;
+ else
+ return CC_REFRESH;
+ }
+ }
+ }
+
+ return CC_ERROR;
+}
+
+static const char *editline_prompt( EditLine *e )
+{
+ // Something like: "\1\033[7m\1Srcds$\1\033[0m\1 "
+ static const char *szPrompt = getenv( "SRCDS_PROMPT" );
+ return szPrompt ? szPrompt : "";
+}
+
+static void editline_cleanup_handler( void *arg )
+{
+ if ( arg )
+ {
+ EditLine *el = (EditLine *)arg;
+ el_end( el );
+ }
+}
+
+static bool add_command( const char *cmd, int cmd_len )
+{
+ if ( cmd )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ // Trim trailing whitespace.
+ while ( ( cmd_len > 0 ) && isspace( cmd[ cmd_len - 1 ] ) )
+ cmd_len--;
+
+ if ( cmd_len > 0 )
+ {
+ pthread_mutex_lock( &g_lock );
+ if ( g_Commands.Count() < 32 )
+ {
+ CUtlString szCommand( cmd, cmd_len );
+ g_Commands.AddToTail( szCommand );
+
+ g_ProcessingCommands = true;
+ }
+ pthread_mutex_unlock( &g_lock );
+
+ // Wait a bit until we've processed the command we added.
+ for ( int i = 0; i < 6; i++ )
+ {
+ while ( g_ProcessingCommands )
+ usleep( 500 );
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void *editline_threadproc( void *arg )
+{
+ HistEvent ev;
+ EditLine *el;
+ History *myhistory;
+ FILE *tty = (FILE *)arg;
+
+ ThreadSetDebugName( "libedit" );
+
+ // Set up state
+ el = el_init( "srcds_linux", stdin, tty, stderr );
+ el_set( el, EL_PROMPT, &editline_prompt );
+ el_set( el, EL_EDITOR, "emacs" ); // or "vi"
+
+ // Hitting Ctrl+R will reset prompt.
+ el_set( el, EL_BIND, "^R", "ed-redisplay", NULL );
+
+ /* Add a user-defined function */
+ el_set( el, EL_ADDFN, "ed-complete", "Complete argument", editline_complete );
+ /* Bind tab to it */
+ el_set( el, EL_BIND, "^I", "ed-complete", NULL );
+
+ // Init history.
+ myhistory = history_init();
+ if (myhistory == 0)
+ {
+ fprintf( stderr, "history could not be initialized\n" );
+ g_threadid = (pthread_t)-1;
+ return (void *)-1;
+ }
+
+ // History size.
+ history( myhistory, &ev, H_SETSIZE, 800 );
+
+ // History callback.
+ el_set( el, EL_HIST, history, myhistory );
+
+ // Source user's defaults.
+ el_source( el, NULL );
+
+ pthread_cleanup_push( editline_cleanup_handler, el );
+
+ while ( g_threadid != (pthread_t)-1 )
+ {
+ // count is the number of characters read.
+ // line is a const char* of our command line with the tailing \n
+ int count;
+ const char *line = el_gets( el, &count );
+
+ if ( add_command( line, count ) )
+ {
+ // Add command to history.
+ history( myhistory, &ev, H_ENTER, line );
+ }
+ }
+
+ pthread_cleanup_pop( 0 );
+
+ // Clean up...
+ history_end( myhistory );
+ el_end( el );
+ return NULL;
+}
+
+static void *fgets_threadproc( void *arg )
+{
+ pthread_cleanup_push( editline_cleanup_handler, NULL );
+
+ while ( g_threadid != (pthread_t)-1 )
+ {
+ char cmd[ 512 ];
+
+ if ( fgets( cmd, sizeof( cmd ), stdin ) )
+ {
+ cmd[ sizeof(cmd) - 1 ] = 0;
+ add_command( cmd, strlen( cmd ) );
+ }
+ }
+
+ pthread_cleanup_pop( 0 );
+ return NULL;
+}
+
+bool CTextConsoleUnix::Init()
+{
+ if( g_threadid != (pthread_t)-1 )
+ {
+ Assert( !"CTextConsoleUnix can only handle a single thread!" );
+ return false;
+ }
+
+ pthread_mutex_init( &g_lock, NULL );
+
+ // This code is for echo-ing key presses to the connected tty
+ // (which is != STDOUT)
+ if ( isatty( STDIN_FILENO ) )
+ {
+ const char *termid_str = ctermid( NULL );
+
+ m_tty = fopen( termid_str, "w+" );
+ if ( !m_tty )
+ {
+ fprintf( stderr, "WARNING: Unable to open tty(%s) for output.\n", termid_str );
+ m_tty = stdout;
+ }
+
+ void *(*terminal_threadproc) (void *) = editline_threadproc;
+ if ( !init_tinfo_functions() )
+ terminal_threadproc = fgets_threadproc;
+
+ if ( pthread_create( &g_threadid, NULL, terminal_threadproc, (void *)m_tty ) != 0 )
+ {
+ g_threadid = (pthread_t)-1;
+ fprintf( stderr, "WARNING: pthread_create failed: %s.\n", strerror(errno) );
+ }
+ }
+ else
+ {
+ m_tty = fopen( "/dev/null", "w+" );
+ if ( !m_tty )
+ m_tty = stdout;
+ }
+
+ m_bConDebug = CommandLine()->FindParm( "-condebug" ) != 0;
+ if ( m_bConDebug && CommandLine()->FindParm( "-conclearlog" ) )
+ g_pFullFileSystem->RemoveFile( CONSOLE_LOG_FILE, "GAME" );
+
+ return CTextConsole::Init();
+}
+
+void CTextConsoleUnix::ShutDown()
+{
+ if ( g_threadid != (pthread_t)-1 )
+ {
+ void *status = NULL;
+ pthread_t tid = g_threadid;
+
+ g_threadid = (pthread_t)-1;
+
+ pthread_cancel( tid );
+ pthread_join( tid, &status );
+ }
+
+ pthread_mutex_destroy( &g_lock );
+}
+
+void CTextConsoleUnix::Print( char * pszMsg )
+{
+ int nChars = strlen( pszMsg );
+
+ if ( nChars > 0 )
+ {
+ if ( m_bConDebug )
+ {
+ FileHandle_t fh = g_pFullFileSystem->Open( CONSOLE_LOG_FILE, "a" );
+ if ( fh != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFullFileSystem->Write( pszMsg, nChars, fh );
+ g_pFullFileSystem->Close( fh );
+ }
+ }
+
+ fwrite( pszMsg, 1, nChars, m_tty );
+ }
+}
+
+void CTextConsoleUnix::SetTitle( char *pszTitle )
+{
+}
+
+void CTextConsoleUnix::SetStatusLine( char *pszStatus )
+{
+}
+
+void CTextConsoleUnix::UpdateStatus()
+{
+}
+
+char *CTextConsoleUnix::GetLine( int index, char *buf, int buflen )
+{
+ if ( g_threadid != (pthread_t)-1 )
+ {
+ if ( g_Commands.Count() > 0 )
+ {
+ pthread_mutex_lock( &g_lock );
+
+ const CUtlString& psCommand = g_Commands[ g_Commands.Head() ];
+ V_strncpy( buf, psCommand.Get(), buflen );
+ g_Commands.Remove( g_Commands.Head() );
+
+ pthread_mutex_unlock( &g_lock );
+ return buf;
+ }
+ else if ( index == 0 )
+ {
+ // We're being asked for the first command. Must be a new frame.
+ // Reset the processed commands global.
+ g_ProcessingCommands = false;
+ }
+ }
+
+ return NULL;
+}
+
+int CTextConsoleUnix::GetWidth()
+{
+ int nWidth = 0;
+ struct winsize ws;
+
+ if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, &ws ) == 0 )
+ nWidth = (int)ws.ws_col;
+
+ if ( nWidth <= 1 )
+ nWidth = 80;
+
+ return nWidth;
+}
+
+#endif // !_WIN32
diff --git a/dedicated/console/TextConsoleUnix.h b/dedicated/console/TextConsoleUnix.h
new file mode 100644
index 0000000..b32fe12
--- /dev/null
+++ b/dedicated/console/TextConsoleUnix.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// TextConsoleUnix.h: Unix interface for the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined TEXTCONSOLE_UNIX_H
+#define TEXTCONSOLE_UNIX_H
+
+#ifndef _WIN32
+
+#include <stdio.h>
+#include "textconsole.h"
+
+class CTextConsoleUnix : public CTextConsole
+{
+public:
+ virtual ~CTextConsoleUnix() { }
+
+ // CTextConsole
+ bool Init();
+ void ShutDown();
+ void Print( char * pszMsg );
+
+ void SetTitle( char *pszTitle );
+ void SetStatusLine( char *pszStatus );
+ void UpdateStatus();
+
+ char * GetLine( int index, char *buf, int buflen );
+ int GetWidth();
+
+private:
+ bool m_bConDebug;
+ FILE *m_tty;
+};
+
+#endif // _ndef WIN32
+
+#endif // !defined TEXTCONSOLE_UNIX_H
diff --git a/dedicated/console/TextConsoleWin32.cpp b/dedicated/console/TextConsoleWin32.cpp
new file mode 100644
index 0000000..ece1eff
--- /dev/null
+++ b/dedicated/console/TextConsoleWin32.cpp
@@ -0,0 +1,644 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// CTextConsoleWin32.cpp: Win32 implementation of the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "TextConsoleWin32.h"
+#include "tier0/dbg.h"
+#include "utlvector.h"
+
+// Could possibly switch all this code over to using readline. This:
+// http://mingweditline.sourceforge.net/?Description
+// readline() / add_history(char *)
+
+#ifdef _WIN32
+
+BOOL WINAPI ConsoleHandlerRoutine( DWORD CtrlType )
+{
+ NOTE_UNUSED( CtrlType );
+ /* TODO ?
+ if ( CtrlType != CTRL_C_EVENT && CtrlType != CTRL_BREAK_EVENT )
+ m_System->Stop(); // don't quit on break or ctrl+c
+ */
+
+ return TRUE;
+}
+
+// GetConsoleHwnd() helper function from MSDN Knowledge Base Article Q124103
+// needed, because HWND GetConsoleWindow(VOID) is not avaliable under Win95/98/ME
+
+HWND GetConsoleHwnd(void)
+{
+ typedef HWND (WINAPI *PFNGETCONSOLEWINDOW)( VOID );
+ static PFNGETCONSOLEWINDOW s_pfnGetConsoleWindow = (PFNGETCONSOLEWINDOW) GetProcAddress( GetModuleHandle("kernel32"), "GetConsoleWindow" );
+ if ( s_pfnGetConsoleWindow )
+ return s_pfnGetConsoleWindow();
+
+ HWND hwndFound; // This is what is returned to the caller.
+ char pszNewWindowTitle[1024]; // Contains fabricated WindowTitle
+ char pszOldWindowTitle[1024]; // Contains original WindowTitle
+
+ // Fetch current window title.
+ GetConsoleTitle( pszOldWindowTitle, 1024 );
+
+ // Format a "unique" NewWindowTitle.
+ wsprintf( pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId() );
+
+ // Change current window title.
+ SetConsoleTitle(pszNewWindowTitle);
+
+ // Ensure window title has been updated.
+ Sleep(40);
+
+ // Look for NewWindowTitle.
+ hwndFound = FindWindow( NULL, pszNewWindowTitle );
+
+ // Restore original window title.
+
+ SetConsoleTitle( pszOldWindowTitle );
+
+ return hwndFound;
+}
+
+CTextConsoleWin32::CTextConsoleWin32()
+{
+ hinput = NULL;
+ houtput = NULL;
+ Attrib = 0;
+ statusline[0] = '\0';
+}
+
+bool CTextConsoleWin32::Init()
+{
+ (void) AllocConsole();
+ SetTitle( "SOURCE DEDICATED SERVER" );
+
+ hinput = GetStdHandle ( STD_INPUT_HANDLE );
+ houtput = GetStdHandle ( STD_OUTPUT_HANDLE );
+
+ if ( !SetConsoleCtrlHandler( &ConsoleHandlerRoutine, TRUE) )
+ {
+ Print( "WARNING! TextConsole::Init: Could not attach console hook.\n" );
+ }
+
+ Attrib = FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY ;
+
+ SetWindowPos( GetConsoleHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW );
+
+ memset( m_szConsoleText, 0, sizeof( m_szConsoleText ) );
+ m_nConsoleTextLen = 0;
+ m_nCursorPosition = 0;
+
+ memset( m_szSavedConsoleText, 0, sizeof( m_szSavedConsoleText ) );
+ m_nSavedConsoleTextLen = 0;
+
+ memset( m_aszLineBuffer, 0, sizeof( m_aszLineBuffer ) );
+ m_nTotalLines = 0;
+ m_nInputLine = 0;
+ m_nBrowseLine = 0;
+
+ // these are log messages, not related to console
+ Msg( "\n" );
+ Msg( "Console initialized.\n" );
+
+ return CTextConsole::Init();
+}
+
+void CTextConsoleWin32::ShutDown( void )
+{
+ FreeConsole();
+}
+
+void CTextConsoleWin32::SetVisible( bool visible )
+{
+ ShowWindow ( GetConsoleHwnd(), visible ? SW_SHOW : SW_HIDE );
+ m_ConsoleVisible = visible;
+}
+
+char * CTextConsoleWin32::GetLine( int index, char *buf, int buflen )
+{
+ while ( 1 )
+ {
+ INPUT_RECORD recs[ 1024 ];
+ unsigned long numread;
+ unsigned long numevents;
+
+ if ( !GetNumberOfConsoleInputEvents( hinput, &numevents ) )
+ {
+ Error("CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents");
+ return NULL;
+ }
+
+ if ( numevents <= 0 )
+ break;
+
+ if ( !ReadConsoleInput( hinput, recs, ARRAYSIZE( recs ), &numread ) )
+ {
+ Error("CTextConsoleWin32::GetLine: !ReadConsoleInput");
+ return NULL;
+ }
+
+ if ( numread == 0 )
+ return NULL;
+
+ for ( int i=0; i < (int)numread; i++ )
+ {
+ INPUT_RECORD *pRec = &recs[i];
+ if ( pRec->EventType != KEY_EVENT )
+ continue;
+
+ if ( pRec->Event.KeyEvent.bKeyDown )
+ {
+ // check for cursor keys
+ if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_UP )
+ {
+ ReceiveUpArrow();
+ }
+ else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_DOWN )
+ {
+ ReceiveDownArrow();
+ }
+ else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_LEFT )
+ {
+ ReceiveLeftArrow();
+ }
+ else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT )
+ {
+ ReceiveRightArrow();
+ }
+ else
+ {
+ char ch;
+ int nLen;
+
+ ch = pRec->Event.KeyEvent.uChar.AsciiChar;
+ switch ( ch )
+ {
+ case '\r': // Enter
+ nLen = ReceiveNewline();
+ if ( nLen )
+ {
+ strncpy( buf, m_szConsoleText, buflen );
+ buf[ buflen - 1 ] = 0;
+ return buf;
+ }
+ break;
+
+ case '\b': // Backspace
+ ReceiveBackspace();
+ break;
+
+ case '\t': // TAB
+ ReceiveTab();
+ break;
+
+ default:
+ if ( ( ch >= ' ') && ( ch <= '~' ) ) // dont' accept nonprintable chars
+ {
+ ReceiveStandardChar( ch );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void CTextConsoleWin32::Print( char * pszMsg )
+{
+ if ( m_nConsoleTextLen )
+ {
+ int nLen;
+
+ nLen = m_nConsoleTextLen;
+
+ while ( nLen-- )
+ {
+ PrintRaw( "\b \b" );
+ }
+ }
+
+ PrintRaw( pszMsg );
+
+ if ( m_nConsoleTextLen )
+ {
+ PrintRaw( m_szConsoleText, m_nConsoleTextLen );
+ }
+
+ UpdateStatus();
+}
+
+void CTextConsoleWin32::PrintRaw( const char * pszMsg, int nChars )
+{
+ unsigned long dummy;
+
+ if ( houtput == NULL )
+ {
+ houtput = GetStdHandle ( STD_OUTPUT_HANDLE );
+ if ( houtput == NULL )
+ return;
+ }
+
+ if ( nChars <= 0 )
+ {
+ nChars = strlen( pszMsg );
+ if ( nChars <= 0 )
+ return;
+ }
+
+ // filter out ASCII BEL characters because windows actually plays a
+ // bell sound, which can be used to lag the server in a DOS attack.
+ char * pTempBuf = NULL;
+ for ( int i = 0; i < nChars; ++i )
+ {
+ if ( pszMsg[i] == 0x07 /*BEL*/ )
+ {
+ if ( !pTempBuf )
+ {
+ pTempBuf = ( char * ) malloc( nChars );
+ memcpy( pTempBuf, pszMsg, nChars );
+ }
+ pTempBuf[i] = '.';
+ }
+ }
+
+ WriteFile( houtput, pTempBuf ? pTempBuf : pszMsg, nChars, &dummy, NULL );
+
+ free( pTempBuf ); // usually NULL
+}
+
+int CTextConsoleWin32::GetWidth( void )
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ int nWidth;
+
+ nWidth = 0;
+
+ if ( GetConsoleScreenBufferInfo( houtput, &csbi ) )
+ {
+ nWidth = csbi.dwSize.X;
+ }
+
+ if ( nWidth <= 1 )
+ nWidth = 80;
+
+ return nWidth;
+}
+
+void CTextConsoleWin32::SetStatusLine( char * pszStatus )
+{
+ strncpy( statusline, pszStatus, 80 );
+ statusline[ 79 ] = '\0';
+ UpdateStatus();
+}
+
+void CTextConsoleWin32::UpdateStatus( void )
+{
+ COORD coord;
+ DWORD dwWritten = 0;
+ WORD wAttrib[ 80 ];
+
+ for ( int i = 0; i < 80; i++ )
+ {
+ wAttrib[i] = Attrib; //FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY ;
+ }
+
+ coord.X = coord.Y = 0;
+
+ WriteConsoleOutputAttribute( houtput, wAttrib, 80, coord, &dwWritten );
+ WriteConsoleOutputCharacter( houtput, statusline, 80, coord, &dwWritten );
+}
+
+
+void CTextConsoleWin32::SetTitle( char * pszTitle )
+{
+ SetConsoleTitle( pszTitle );
+}
+
+void CTextConsoleWin32::SetColor(WORD attrib)
+{
+ Attrib = attrib;
+}
+
+int CTextConsoleWin32::ReceiveNewline( void )
+{
+ int nLen = 0;
+
+ PrintRaw( "\n" );
+
+ if ( m_nConsoleTextLen )
+ {
+ nLen = m_nConsoleTextLen;
+
+ m_szConsoleText[ m_nConsoleTextLen ] = 0;
+ m_nConsoleTextLen = 0;
+ m_nCursorPosition = 0;
+
+ // cache line in buffer, but only if it's not a duplicate of the previous line
+ if ( ( m_nInputLine == 0 ) || ( strcmp( m_aszLineBuffer[ m_nInputLine - 1 ], m_szConsoleText ) ) )
+ {
+ strncpy( m_aszLineBuffer[ m_nInputLine ], m_szConsoleText, MAX_CONSOLE_TEXTLEN );
+
+ m_nInputLine++;
+
+ if ( m_nInputLine > m_nTotalLines )
+ m_nTotalLines = m_nInputLine;
+
+ if ( m_nInputLine >= MAX_BUFFER_LINES )
+ m_nInputLine = 0;
+
+ }
+
+ m_nBrowseLine = m_nInputLine;
+ }
+
+ return nLen;
+}
+
+
+void CTextConsoleWin32::ReceiveBackspace( void )
+{
+ int nCount;
+
+ if ( m_nCursorPosition == 0 )
+ {
+ return;
+ }
+
+ m_nConsoleTextLen--;
+ m_nCursorPosition--;
+
+ PrintRaw( "\b" );
+
+ for ( nCount = m_nCursorPosition; nCount < m_nConsoleTextLen; nCount++ )
+ {
+ m_szConsoleText[ nCount ] = m_szConsoleText[ nCount + 1 ];
+ PrintRaw( m_szConsoleText + nCount, 1 );
+ }
+
+ PrintRaw( " " );
+
+ nCount = m_nConsoleTextLen;
+ while ( nCount >= m_nCursorPosition )
+ {
+ PrintRaw( "\b" );
+ nCount--;
+ }
+
+ m_nBrowseLine = m_nInputLine;
+}
+
+
+void CTextConsoleWin32::ReceiveTab( void )
+{
+ CUtlVector<char *> matches;
+
+ m_szConsoleText[ m_nConsoleTextLen ] = 0;
+
+ if ( matches.Count() == 0 )
+ {
+ return;
+ }
+
+ if ( matches.Count() == 1 )
+ {
+ char * pszCmdName;
+ char * pszRest;
+
+ pszCmdName = matches[0];
+ pszRest = pszCmdName + strlen( m_szConsoleText );
+
+ if ( pszRest )
+ {
+ PrintRaw( pszRest );
+ strcat( m_szConsoleText, pszRest );
+ m_nConsoleTextLen += strlen( pszRest );
+
+ PrintRaw( " " );
+ strcat( m_szConsoleText, " " );
+ m_nConsoleTextLen++;
+ }
+ }
+ else
+ {
+ int nLongestCmd;
+ int nTotalColumns;
+ int nCurrentColumn;
+ char * pszCurrentCmd;
+ int i = 0;
+
+ nLongestCmd = 0;
+
+ pszCurrentCmd = matches[0];
+ while ( pszCurrentCmd )
+ {
+ if ( (int)strlen( pszCurrentCmd) > nLongestCmd )
+ {
+ nLongestCmd = strlen( pszCurrentCmd);
+ }
+
+ i++;
+ pszCurrentCmd = (char *)matches[i];
+ }
+
+ nTotalColumns = ( GetWidth() - 1 ) / ( nLongestCmd + 1 );
+ nCurrentColumn = 0;
+
+ PrintRaw( "\n" );
+
+ // Would be nice if these were sorted, but not that big a deal
+ pszCurrentCmd = matches[0];
+ i = 0;
+ while ( pszCurrentCmd )
+ {
+ char szFormatCmd[ 256 ];
+
+ nCurrentColumn++;
+
+ if ( nCurrentColumn > nTotalColumns )
+ {
+ PrintRaw( "\n" );
+ nCurrentColumn = 1;
+ }
+
+ Q_snprintf( szFormatCmd, sizeof(szFormatCmd), "%-*s ", nLongestCmd, pszCurrentCmd );
+ PrintRaw( szFormatCmd );
+
+ i++;
+ pszCurrentCmd = matches[i];
+ }
+
+ PrintRaw( "\n" );
+ PrintRaw( m_szConsoleText );
+ // TODO: Tack on 'common' chars in all the matches, i.e. if I typed 'con' and all the
+ // matches begin with 'connect_' then print the matches but also complete the
+ // command up to that point at least.
+ }
+
+ m_nCursorPosition = m_nConsoleTextLen;
+ m_nBrowseLine = m_nInputLine;
+}
+
+
+
+void CTextConsoleWin32::ReceiveStandardChar( const char ch )
+{
+ int nCount;
+
+ // If the line buffer is maxed out, ignore this char
+ if ( m_nConsoleTextLen >= ( sizeof( m_szConsoleText ) - 2 ) )
+ {
+ return;
+ }
+
+ nCount = m_nConsoleTextLen;
+ while ( nCount > m_nCursorPosition )
+ {
+ m_szConsoleText[ nCount ] = m_szConsoleText[ nCount - 1 ];
+ nCount--;
+ }
+
+ m_szConsoleText[ m_nCursorPosition ] = ch;
+
+ PrintRaw( m_szConsoleText + m_nCursorPosition, m_nConsoleTextLen - m_nCursorPosition + 1 );
+
+ m_nConsoleTextLen++;
+ m_nCursorPosition++;
+
+ nCount = m_nConsoleTextLen;
+ while ( nCount > m_nCursorPosition )
+ {
+ PrintRaw( "\b" );
+ nCount--;
+ }
+
+ m_nBrowseLine = m_nInputLine;
+}
+
+
+void CTextConsoleWin32::ReceiveUpArrow( void )
+{
+ int nLastCommandInHistory;
+
+ nLastCommandInHistory = m_nInputLine + 1;
+ if ( nLastCommandInHistory > m_nTotalLines )
+ {
+ nLastCommandInHistory = 0;
+ }
+
+ if ( m_nBrowseLine == nLastCommandInHistory )
+ {
+ return;
+ }
+
+ if ( m_nBrowseLine == m_nInputLine )
+ {
+ if ( m_nConsoleTextLen > 0 )
+ {
+ // Save off current text
+ strncpy( m_szSavedConsoleText, m_szConsoleText, m_nConsoleTextLen );
+ // No terminator, it's a raw buffer we always know the length of
+ }
+
+ m_nSavedConsoleTextLen = m_nConsoleTextLen;
+ }
+
+ m_nBrowseLine--;
+ if ( m_nBrowseLine < 0 )
+ {
+ m_nBrowseLine = m_nTotalLines - 1;
+ }
+
+ while ( m_nConsoleTextLen-- ) // delete old line
+ {
+ PrintRaw( "\b \b" );
+ }
+
+ // copy buffered line
+ PrintRaw( m_aszLineBuffer[ m_nBrowseLine ] );
+
+ strncpy( m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN );
+ m_nConsoleTextLen = strlen( m_aszLineBuffer[ m_nBrowseLine ] );
+
+ m_nCursorPosition = m_nConsoleTextLen;
+}
+
+
+void CTextConsoleWin32::ReceiveDownArrow( void )
+{
+ if ( m_nBrowseLine == m_nInputLine )
+ {
+ return;
+ }
+
+ m_nBrowseLine++;
+ if ( m_nBrowseLine > m_nTotalLines )
+ {
+ m_nBrowseLine = 0;
+ }
+
+ while ( m_nConsoleTextLen-- ) // delete old line
+ {
+ PrintRaw( "\b \b" );
+ }
+
+ if ( m_nBrowseLine == m_nInputLine )
+ {
+ if ( m_nSavedConsoleTextLen > 0 )
+ {
+ // Restore current text
+ strncpy( m_szConsoleText, m_szSavedConsoleText, m_nSavedConsoleTextLen );
+ // No terminator, it's a raw buffer we always know the length of
+
+ PrintRaw( m_szConsoleText, m_nSavedConsoleTextLen );
+ }
+
+ m_nConsoleTextLen = m_nSavedConsoleTextLen;
+ }
+ else
+ {
+ // copy buffered line
+ PrintRaw( m_aszLineBuffer[ m_nBrowseLine ] );
+
+ strncpy( m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN );
+
+ m_nConsoleTextLen = strlen( m_aszLineBuffer[ m_nBrowseLine ] );
+ }
+
+ m_nCursorPosition = m_nConsoleTextLen;
+}
+
+
+void CTextConsoleWin32::ReceiveLeftArrow( void )
+{
+ if ( m_nCursorPosition == 0 )
+ {
+ return;
+ }
+
+ PrintRaw( "\b" );
+ m_nCursorPosition--;
+}
+
+
+void CTextConsoleWin32::ReceiveRightArrow( void )
+{
+ if ( m_nCursorPosition == m_nConsoleTextLen )
+ {
+ return;
+ }
+
+ PrintRaw( m_szConsoleText + m_nCursorPosition, 1 );
+ m_nCursorPosition++;
+}
+
+#endif // _WIN32
diff --git a/dedicated/console/TextConsoleWin32.h b/dedicated/console/TextConsoleWin32.h
new file mode 100644
index 0000000..4c762ec
--- /dev/null
+++ b/dedicated/console/TextConsoleWin32.h
@@ -0,0 +1,82 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// TextConsoleWin32.h: Win32 interface for the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined TEXTCONSOLE_WIN32_H
+#define TEXTCONSOLE_WIN32_H
+#pragma once
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include "TextConsole.h"
+
+#define MAX_CONSOLE_TEXTLEN 256
+#define MAX_BUFFER_LINES 30
+
+class CTextConsoleWin32 : public CTextConsole
+{
+public:
+ CTextConsoleWin32();
+ virtual ~CTextConsoleWin32() { };
+
+ // CTextConsole
+ bool Init();
+ void ShutDown( void );
+ void Print( char *pszMsg );
+
+ void SetTitle( char * pszTitle );
+ void SetStatusLine( char * pszStatus );
+ void UpdateStatus( void );
+
+ char * GetLine( int index, char *buf, int buflen );
+ int GetWidth( void );
+
+ void SetVisible( bool visible );
+
+protected:
+ // CTextConsoleWin32
+ void SetColor( WORD );
+ void PrintRaw( const char * pszMsg, int nChars = -1 );
+
+private:
+ char m_szConsoleText[ MAX_CONSOLE_TEXTLEN ]; // console text buffer
+ int m_nConsoleTextLen; // console textbuffer length
+ int m_nCursorPosition; // position in the current input line
+
+ // Saved input data when scrolling back through command history
+ char m_szSavedConsoleText[ MAX_CONSOLE_TEXTLEN ]; // console text buffer
+ int m_nSavedConsoleTextLen; // console textbuffer length
+
+ char m_aszLineBuffer[ MAX_BUFFER_LINES ][ MAX_CONSOLE_TEXTLEN ]; // command buffer last MAX_BUFFER_LINES commands
+ int m_nInputLine; // Current line being entered
+ int m_nBrowseLine; // current buffer line for up/down arrow
+ int m_nTotalLines; // # of nonempty lines in the buffer
+
+ int ReceiveNewline( void );
+ void ReceiveBackspace( void );
+ void ReceiveTab( void );
+ void ReceiveStandardChar( const char ch );
+ void ReceiveUpArrow( void );
+ void ReceiveDownArrow( void );
+ void ReceiveLeftArrow( void );
+ void ReceiveRightArrow( void );
+
+private:
+ HANDLE hinput; // standard input handle
+ HANDLE houtput; // standard output handle
+ WORD Attrib; // attrib colours for status bar
+
+ char statusline[81]; // first line in console is status line
+};
+
+#endif // _WIN32
+
+#endif // !defined TEXTCONSOLE_WIN32_H
diff --git a/dedicated/console/conproc.cpp b/dedicated/console/conproc.cpp
new file mode 100644
index 0000000..2156450
--- /dev/null
+++ b/dedicated/console/conproc.cpp
@@ -0,0 +1,428 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#ifdef _WIN32
+// conproc.c -- support for qhost
+#include <stdio.h>
+#include <process.h>
+#include <windows.h>
+#include "conproc.h"
+#include "isys.h"
+#include "tier0/icommandline.h"
+#include "tier1/strtools.h"
+
+static HANDLE heventDone;
+static HANDLE hfileBuffer;
+static HANDLE heventChildSend;
+static HANDLE heventParentSend;
+static HANDLE hStdout;
+static HANDLE hStdin;
+
+/*
+==============
+SetConsoleCXCY
+
+==============
+*/
+BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
+{
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD coordMax;
+
+ coordMax = GetLargestConsoleWindowSize(hStdout);
+
+ if (cy > coordMax.Y)
+ cy = coordMax.Y;
+
+ if (cx > coordMax.X)
+ cx = coordMax.X;
+
+ if (!GetConsoleScreenBufferInfo(hStdout, &info))
+ return FALSE;
+
+// height
+ info.srWindow.Left = 0;
+ info.srWindow.Right = info.dwSize.X - 1;
+ info.srWindow.Top = 0;
+ info.srWindow.Bottom = cy - 1;
+
+ if (cy < info.dwSize.Y)
+ {
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+
+ info.dwSize.Y = cy;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+ }
+ else if (cy > info.dwSize.Y)
+ {
+ info.dwSize.Y = cy;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+ }
+
+ if (!GetConsoleScreenBufferInfo(hStdout, &info))
+ return FALSE;
+
+// width
+ info.srWindow.Left = 0;
+ info.srWindow.Right = cx - 1;
+ info.srWindow.Top = 0;
+ info.srWindow.Bottom = info.dwSize.Y - 1;
+
+ if (cx < info.dwSize.X)
+ {
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+
+ info.dwSize.X = cx;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+ }
+ else if (cx > info.dwSize.X)
+ {
+ info.dwSize.X = cx;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+==============
+GetMappedBuffer
+
+==============
+*/
+LPVOID GetMappedBuffer (HANDLE hfileBuffer)
+{
+ LPVOID pBuffer;
+
+ pBuffer = MapViewOfFile (hfileBuffer,
+ FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
+
+ return pBuffer;
+}
+
+/*
+==============
+ReleaseMappedBuffer
+
+==============
+*/
+void ReleaseMappedBuffer (LPVOID pBuffer)
+{
+ UnmapViewOfFile (pBuffer);
+}
+
+/*
+==============
+GetScreenBufferLines
+
+==============
+*/
+BOOL GetScreenBufferLines (int *piLines)
+{
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ BOOL bRet;
+
+ bRet = GetConsoleScreenBufferInfo (hStdout, &info);
+
+ if (bRet)
+ *piLines = info.dwSize.Y;
+
+ return bRet;
+}
+
+/*
+==============
+SetScreenBufferLines
+
+==============
+*/
+BOOL SetScreenBufferLines (int iLines)
+{
+ return SetConsoleCXCY (hStdout, 80, iLines);
+}
+
+/*
+==============
+ReadText
+
+==============
+*/
+BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
+{
+ COORD coord;
+ DWORD dwRead;
+ BOOL bRet;
+
+ coord.X = 0;
+ coord.Y = iBeginLine;
+
+ bRet = ReadConsoleOutputCharacter(
+ hStdout,
+ pszText,
+ 80 * (iEndLine - iBeginLine + 1),
+ coord,
+ &dwRead);
+
+ // Make sure it's null terminated.
+ if (bRet)
+ pszText[dwRead] = '\0';
+
+ return bRet;
+}
+
+/*
+==============
+CharToCode
+
+==============
+*/
+int CharToCode (char c)
+{
+ char upper;
+
+ upper = toupper(c);
+
+ switch (c)
+ {
+ case 13:
+ return 28;
+
+ default:
+ break;
+ }
+
+ if (V_isalpha(c))
+ return (30 + upper - 65);
+
+ if (V_isdigit(c))
+ return (1 + upper - 47);
+
+ return c;
+}
+
+/*
+==============
+WriteText
+
+==============
+*/
+BOOL WriteText (LPCTSTR szText)
+{
+ DWORD dwWritten;
+ INPUT_RECORD rec;
+ char upper, *sz;
+
+ sz = (LPTSTR) szText;
+
+ while (*sz)
+ {
+ // 13 is the code for a carriage return (\n) instead of 10.
+ if (*sz == 10)
+ *sz = 13;
+
+ upper = toupper(*sz);
+
+ rec.EventType = KEY_EVENT;
+ rec.Event.KeyEvent.bKeyDown = TRUE;
+ rec.Event.KeyEvent.wRepeatCount = 1;
+ rec.Event.KeyEvent.wVirtualKeyCode = upper;
+ rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
+ rec.Event.KeyEvent.uChar.AsciiChar = *sz;
+ rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
+ rec.Event.KeyEvent.dwControlKeyState = V_isupper(*sz) ? 0x80 : 0x0;
+
+ WriteConsoleInput(
+ hStdin,
+ &rec,
+ 1,
+ &dwWritten);
+
+ rec.Event.KeyEvent.bKeyDown = FALSE;
+
+ WriteConsoleInput(
+ hStdin,
+ &rec,
+ 1,
+ &dwWritten);
+
+ sz++;
+ }
+
+ return TRUE;
+}
+
+/*
+==============
+RequestProc
+
+==============
+*/
+unsigned _stdcall RequestProc (void *arg)
+{
+ int *pBuffer;
+ DWORD dwRet;
+ HANDLE heventWait[2];
+ int iBeginLine, iEndLine;
+
+ heventWait[0] = heventParentSend;
+ heventWait[1] = heventDone;
+
+ while (1)
+ {
+ dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE);
+
+ // heventDone fired, so we're exiting.
+ if (dwRet == WAIT_OBJECT_0 + 1)
+ break;
+
+ pBuffer = (int *) GetMappedBuffer (hfileBuffer);
+
+ // hfileBuffer is invalid. Just leave.
+ if (!pBuffer)
+ {
+ sys->Printf ("Request Proc: Invalid -HFILE handle\n");
+ break;
+ }
+
+ switch (pBuffer[0])
+ {
+ case CCOM_WRITE_TEXT:
+ // Param1 : Text
+ pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
+ break;
+
+ case CCOM_GET_TEXT:
+ // Param1 : Begin line
+ // Param2 : End line
+ iBeginLine = pBuffer[1];
+ iEndLine = pBuffer[2];
+ pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine,
+ iEndLine);
+ break;
+
+ case CCOM_GET_SCR_LINES:
+ // No params
+ pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
+ break;
+
+ case CCOM_SET_SCR_LINES:
+ // Param1 : Number of lines
+ pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
+ break;
+ }
+
+ ReleaseMappedBuffer (pBuffer);
+ SetEvent (heventChildSend);
+ }
+
+ _endthreadex (0);
+ return 0;
+}
+
+/*
+==============
+DeinitConProc
+
+==============
+*/
+void DeinitConProc (void)
+{
+ if ( heventDone )
+ {
+ SetEvent ( heventDone );
+ }
+}
+
+/*
+==============
+InitConProc
+
+==============
+*/
+void InitConProc ( void )
+{
+ unsigned threadAddr;
+ HANDLE hFile = (HANDLE)0;
+ HANDLE heventParent = (HANDLE)0;
+ HANDLE heventChild = (HANDLE)0;
+ int WantHeight = 50;
+ const char *p;
+
+ // give external front ends a chance to hook into the console
+ if ( CommandLine()->CheckParm ( "-HFILE", &p ) && p )
+ {
+ hFile = (HANDLE)atoi ( p );
+ }
+
+ if ( CommandLine()->CheckParm ( "-HPARENT", &p ) && p )
+ {
+ heventParent = (HANDLE)atoi ( p );
+ }
+
+ if ( CommandLine()->CheckParm ( "-HCHILD", &p ) && p )
+ {
+ heventChild = (HANDLE)atoi ( p );
+ }
+
+ // ignore if we don't have all the events.
+ if ( !hFile || !heventParent || !heventChild )
+ {
+ //sys->Printf ("\n\nNo external front end present.\n" );
+ return;
+ }
+
+ sys->Printf( "\n\nInitConProc: Setting up external control.\n" );
+
+ hfileBuffer = hFile;
+ heventParentSend = heventParent;
+ heventChildSend = heventChild;
+
+ // So we'll know when to go away.
+ heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
+ if (!heventDone)
+ {
+ sys->Printf ("InitConProc: Couldn't create heventDone\n");
+ return;
+ }
+
+ if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr))
+ {
+ CloseHandle (heventDone);
+ sys->Printf ("InitConProc: Couldn't create third party thread\n");
+ return;
+ }
+
+ // save off the input/output handles.
+ hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
+ hStdin = GetStdHandle (STD_INPUT_HANDLE);
+
+ if ( CommandLine()->CheckParm( "-conheight", &p ) && p )
+ {
+ WantHeight = atoi( p );
+ }
+
+ // Force 80 character width, at least 25 character height
+ SetConsoleCXCY( hStdout, 80, WantHeight );
+}
+#endif // _WIN32
+
diff --git a/dedicated/console/conproc.h b/dedicated/console/conproc.h
new file mode 100644
index 0000000..ef84c42
--- /dev/null
+++ b/dedicated/console/conproc.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// conproc.h -- support for external server monitoring programs
+#ifndef INC_CONPROCH
+#define INC_CONPROCH
+
+#define CCOM_WRITE_TEXT 0x2
+// Param1 : Text
+
+#define CCOM_GET_TEXT 0x3
+// Param1 : Begin line
+// Param2 : End line
+
+#define CCOM_GET_SCR_LINES 0x4
+// No params
+
+#define CCOM_SET_SCR_LINES 0x5
+// Param1 : Number of lines
+
+void InitConProc ( void );
+void DeinitConProc ( void );
+
+void WriteStatusText( char *psz );
+
+#endif // !INC_CONPROCH \ No newline at end of file
diff --git a/dedicated/console/textconsole.cpp b/dedicated/console/textconsole.cpp
new file mode 100644
index 0000000..c52ae23
--- /dev/null
+++ b/dedicated/console/textconsole.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// TextConsole.cpp: implementation of the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "textconsole.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+bool CTextConsole::Init()
+{
+ m_ConsoleVisible = true;
+ return true;
+}
diff --git a/dedicated/console/textconsole.h b/dedicated/console/textconsole.h
new file mode 100644
index 0000000..69cf366
--- /dev/null
+++ b/dedicated/console/textconsole.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#if !defined TEXTCONSOLE_H
+#define TEXTCONSOLE_H
+#pragma once
+
+class CTextConsole
+{
+public:
+ CTextConsole() : m_ConsoleVisible( true ) {}
+ virtual ~CTextConsole() {};
+
+ virtual bool Init ();
+ virtual void ShutDown() = 0;
+ virtual void Print( char * pszMsg ) = 0;
+
+ virtual void SetTitle( char * pszTitle ) = 0;
+ virtual void SetStatusLine( char * pszStatus ) = 0;
+ virtual void UpdateStatus() = 0;
+
+ // Must be provided by children
+ virtual char * GetLine( int index, char *buf, int buflen ) = 0;
+ virtual int GetWidth() = 0;
+
+ virtual void SetVisible( bool visible ) { m_ConsoleVisible = visible; }
+ virtual bool IsVisible() { return m_ConsoleVisible; }
+
+protected:
+ bool m_ConsoleVisible;
+};
+
+#endif // !defined TEXTCONSOLE_H