2008-09-17 10:18:22 +00:00
#define VCMI_DLL
2007-08-15 15:13:11 +00:00
#include "stdafx.h"
2007-08-17 17:42:21 +00:00
#include "CConsoleHandler.h"
2009-06-23 08:14:49 +00:00
#include <boost/function.hpp>
#include <boost/thread.hpp>
2009-07-31 20:10:22 +00:00
#include <iomanip>
2008-09-18 20:24:53 +00:00
2009-07-31 20:10:22 +00:00
/*
* CConsoleHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
2009-06-23 08:14:49 +00:00
#ifndef _WIN32
typedef std :: string TColor ;
#define _kill_thread(a) pthread_cancel(a)
typedef pthread_t ThreadHandle ;
#define CONSOLE_GREEN "\x1b[1;40;32m"
#define CONSOLE_RED "\x1b[1;40;32m"
#define CONSOLE_MAGENTA "\x1b[1;40;35m"
#define CONSOLE_YELLOW "\x1b[1;40;32m"
#define CONSOLE_WHITE "\x1b[1;40;39m"
#define CONSOLE_GRAY "\x1b[0;40;39m"
#else
2009-08-17 13:08:05 +00:00
#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
2009-06-23 18:34:59 +00:00
#include <windows.h>
2009-07-31 20:10:22 +00:00
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
2009-06-23 18:34:59 +00:00
2009-06-23 08:14:49 +00:00
typedef WORD TColor ;
#define _kill_thread(a) TerminateThread(a,0)
HANDLE handleIn ;
HANDLE handleOut ;
typedef void * ThreadHandle ;
#define CONSOLE_GREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define CONSOLE_RED FOREGROUND_RED | FOREGROUND_INTENSITY
#define CONSOLE_MAGENTA FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define CONSOLE_YELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
2008-06-21 13:27:52 +00:00
#endif
2009-06-23 08:14:49 +00:00
TColor defColor ;
2009-07-31 20:10:22 +00:00
#ifdef _WIN32
void printWinError ()
{
//Get error code
int error = GetLastError ();
if ( ! error )
{
tlog0 << "No Win error information set. \n " ;
return ;
}
tlog1 << "Error " << error << " encountered: \n " ;
//Get error description
char * pTemp = NULL ;
FormatMessageA ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM ,
NULL , error , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ), ( LPSTR ) & pTemp , 1 , NULL );
tlog1 << pTemp << std :: endl ;
LocalFree ( pTemp );
}
const char * exceptionName ( DWORD exc )
{
#define EXC_CASE(EXC) case EXCEPTION_##EXC : return "EXCEPTION_" #EXC
switch ( exc )
{
EXC_CASE ( ACCESS_VIOLATION );
EXC_CASE ( DATATYPE_MISALIGNMENT );
EXC_CASE ( BREAKPOINT );
EXC_CASE ( SINGLE_STEP );
EXC_CASE ( ARRAY_BOUNDS_EXCEEDED );
EXC_CASE ( FLT_DENORMAL_OPERAND );
EXC_CASE ( FLT_DIVIDE_BY_ZERO );
EXC_CASE ( FLT_INEXACT_RESULT );
EXC_CASE ( FLT_INVALID_OPERATION );
EXC_CASE ( FLT_OVERFLOW );
EXC_CASE ( FLT_STACK_CHECK );
EXC_CASE ( FLT_UNDERFLOW );
EXC_CASE ( INT_DIVIDE_BY_ZERO );
EXC_CASE ( INT_OVERFLOW );
EXC_CASE ( PRIV_INSTRUCTION );
EXC_CASE ( IN_PAGE_ERROR );
EXC_CASE ( ILLEGAL_INSTRUCTION );
EXC_CASE ( NONCONTINUABLE_EXCEPTION );
EXC_CASE ( STACK_OVERFLOW );
EXC_CASE ( INVALID_DISPOSITION );
EXC_CASE ( GUARD_PAGE );
EXC_CASE ( INVALID_HANDLE );
default :
return "UNKNOWN EXCEPTION" ;
}
#undef EXC_CASE
}
LONG WINAPI onUnhandledException ( EXCEPTION_POINTERS * exception )
{
tlog1 << "Disaster happened. \n " ;
PEXCEPTION_RECORD einfo = exception -> ExceptionRecord ;
tlog1 << "Reason: 0x" << std :: hex << einfo -> ExceptionCode << " - " << exceptionName ( einfo -> ExceptionCode );
tlog1 << " at " << std :: setfill ( '0' ) << std :: setw ( 4 ) << exception -> ContextRecord -> SegCs << ":" << ( void * ) einfo -> ExceptionAddress << std :: endl ;;
if ( einfo -> ExceptionCode == EXCEPTION_ACCESS_VIOLATION )
{
tlog1 << "Attempt to " << ( einfo -> ExceptionInformation [ 0 ] == 1 ? "write to " : "read from " )
<< "0x" << std :: setw ( 8 ) << ( void * ) einfo -> ExceptionInformation [ 1 ] << std :: endl ;;
}
const DWORD threadId = :: GetCurrentThreadId ();
tlog1 << "Thread ID: " << threadId << " [" << std :: dec << std :: setw ( 0 ) << threadId << "] \n " ;
//exception info to be placed in the dump
MINIDUMP_EXCEPTION_INFORMATION meinfo = { threadId , exception , TRUE };
//create file where dump will be placed
char * mname = NULL ;
char buffer [ MAX_PATH + 1 ];
HMODULE hModule = NULL ;
GetModuleFileNameA ( hModule , buffer , MAX_PATH );
mname = strrchr ( buffer , '\\' );
if ( mname != 0 )
mname ++ ;
else
mname = buffer ;
strcat ( mname , "_crashinfo.dmp" );
HANDLE dfile = CreateFileA ( mname , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_WRITE | FILE_SHARE_READ , 0 , CREATE_ALWAYS , 0 , 0 );
2009-10-01 20:00:21 +00:00
tlog1 << "Crash info will be put in " << mname << std :: endl ;
2009-07-31 20:10:22 +00:00
MiniDumpWriteDump ( GetCurrentProcess (), GetCurrentProcessId (), dfile , MiniDumpWithDataSegs , & meinfo , 0 , 0 );
MessageBoxA ( 0 , "VCMI has crashed. We are sorry. File with information about encountered problem has been created." , "VCMI Crashhandler" , MB_OK | MB_ICONERROR );
return EXCEPTION_EXECUTE_HANDLER ;
}
#endif
2008-06-21 13:27:52 +00:00
2009-04-15 14:03:31 +00:00
2008-09-17 10:18:22 +00:00
void CConsoleHandler :: setColor ( int level )
2007-08-15 15:13:11 +00:00
{
2009-06-23 08:14:49 +00:00
TColor color ;
2008-09-17 10:18:22 +00:00
switch ( level )
{
case - 1 :
color = defColor ;
break ;
case 0 :
2009-06-23 08:14:49 +00:00
color = CONSOLE_GREEN ;
2008-09-17 10:18:22 +00:00
break ;
case 1 :
2009-06-23 08:14:49 +00:00
color = CONSOLE_RED ;
2008-09-17 10:18:22 +00:00
break ;
case 2 :
2009-06-23 08:14:49 +00:00
color = CONSOLE_MAGENTA ;
2008-09-17 10:18:22 +00:00
break ;
case 3 :
2009-06-23 08:14:49 +00:00
color = CONSOLE_YELLOW ;
2008-09-17 10:18:22 +00:00
break ;
case 4 :
2009-06-23 08:14:49 +00:00
color = CONSOLE_WHITE ;
2008-09-17 10:18:22 +00:00
break ;
case 5 :
2009-06-23 08:14:49 +00:00
color = CONSOLE_GRAY ;
2008-09-17 10:18:22 +00:00
break ;
default :
color = defColor ;
break ;
}
2008-09-18 20:24:53 +00:00
#ifdef _WIN32
2008-09-17 10:18:22 +00:00
SetConsoleTextAttribute ( handleOut , color );
2008-09-18 20:24:53 +00:00
#else
std :: cout << color ;
2008-09-17 10:18:22 +00:00
#endif
}
int CConsoleHandler :: run ()
{
2008-10-26 20:58:34 +00:00
char buffer [ 5000 ];
2007-08-15 15:13:11 +00:00
while ( true )
{
2008-10-26 20:58:34 +00:00
std :: cin . getline ( buffer , 5000 );
2008-09-17 10:18:22 +00:00
if ( cb && * cb )
( * cb )( buffer );
2007-08-15 15:13:11 +00:00
}
return - 1 ;
}
2008-09-17 10:18:22 +00:00
CConsoleHandler :: CConsoleHandler ()
2007-08-15 15:13:11 +00:00
{
2008-09-18 20:24:53 +00:00
#ifdef _WIN32
2008-09-17 10:18:22 +00:00
handleIn = GetStdHandle ( STD_INPUT_HANDLE );
handleOut = GetStdHandle ( STD_OUTPUT_HANDLE );
CONSOLE_SCREEN_BUFFER_INFO csbi ;
GetConsoleScreenBufferInfo ( handleOut , & csbi );
defColor = csbi . wAttributes ;
2009-08-02 14:21:18 +00:00
#ifndef _DEBUG
2009-07-31 20:10:22 +00:00
SetUnhandledExceptionFilter ( onUnhandledException );
2009-08-02 14:21:18 +00:00
#endif
2008-09-18 20:24:53 +00:00
#else
defColor = " \x1b [0m" ;
2008-09-17 10:18:22 +00:00
#endif
cb = new boost :: function < void ( const std :: string & ) > ;
2009-06-23 08:14:49 +00:00
thread = NULL ;
2007-08-15 15:13:11 +00:00
}
2008-09-17 10:18:22 +00:00
CConsoleHandler ::~ CConsoleHandler ()
{
2009-10-26 05:39:30 +00:00
tlog3 << "Killing console... " ;
end ();
2008-09-17 10:18:22 +00:00
delete cb ;
2009-10-26 05:39:30 +00:00
tlog3 << "done! \n " ;
2008-09-17 10:18:22 +00:00
}
2009-06-23 08:14:49 +00:00
void CConsoleHandler :: end ()
2008-09-18 20:24:53 +00:00
{
2009-10-26 05:39:30 +00:00
if ( thread ) {
ThreadHandle th = ( ThreadHandle ) thread -> native_handle ();
int ret = _kill_thread ( th );
thread -> join ();
delete thread ;
thread = NULL ;
}
2008-09-18 20:24:53 +00:00
}
2009-06-23 08:14:49 +00:00
void CConsoleHandler :: start ()
{
2009-10-31 22:55:05 +00:00
#ifdef _WIN32
2009-06-23 08:14:49 +00:00
thread = new boost :: thread ( boost :: bind ( & CConsoleHandler :: run , console ));
2009-10-31 22:55:05 +00:00
#endif
2009-10-26 05:39:30 +00:00
}