2004-08-23 00:15:46 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
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
2010-12-15 12:29:58 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-23 00:15:46 +00:00
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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2013-03-31 04:21:08 +00:00
# include "quakedef.h"
2004-08-23 00:15:46 +00:00
# include <sys/types.h>
# include <sys/timeb.h>
2004-09-04 17:59:22 +00:00
# ifdef SERVERONLY
2004-08-23 00:15:46 +00:00
# include <winsock.h>
# include <conio.h>
2007-12-30 20:05:49 +00:00
# ifdef MULTITHREAD
# include <process.h>
# endif
2004-08-23 00:15:46 +00:00
# ifndef MINIMAL
2004-12-13 00:44:43 +00:00
//#define USESERVICE
2004-08-23 00:15:46 +00:00
# endif
2005-11-14 01:32:21 +00:00
# define SERVICENAME DISTRIBUTION"SV"
2004-08-23 00:15:46 +00:00
2004-12-13 00:44:43 +00:00
2005-10-04 21:16:47 +00:00
static HANDLE hconsoleout ;
2009-03-07 05:05:54 +00:00
2010-07-18 08:42:59 +00:00
# ifdef _DEBUG
# if _MSC_VER >= 1300
# define CATCHCRASH
# endif
# endif
# ifdef CATCHCRASH
# include "dbghelp.h"
typedef BOOL ( WINAPI * MINIDUMPWRITEDUMP ) (
HANDLE hProcess ,
DWORD ProcessId ,
HANDLE hFile ,
MINIDUMP_TYPE DumpType ,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam ,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam ,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
) ;
DWORD CrashExceptionHandler ( DWORD exceptionCode , LPEXCEPTION_POINTERS exceptionInfo )
{
char dumpPath [ 1024 ] ;
HANDLE hProc = GetCurrentProcess ( ) ;
DWORD procid = GetCurrentProcessId ( ) ;
HANDLE dumpfile ;
HMODULE hDbgHelp ;
MINIDUMPWRITEDUMP fnMiniDumpWriteDump ;
HMODULE hKernel ;
BOOL ( WINAPI * pIsDebuggerPresent ) ( void ) ;
hKernel = LoadLibrary ( " kernel32 " ) ;
pIsDebuggerPresent = ( void * ) GetProcAddress ( hKernel , " IsDebuggerPresent " ) ;
# ifdef GLQUAKE
GLVID_Crashed ( ) ;
# endif
if ( pIsDebuggerPresent ( ) )
{
/*if we have a current window, minimize it to bring us out of fullscreen*/
return EXCEPTION_CONTINUE_SEARCH ;
}
hDbgHelp = LoadLibrary ( " DBGHELP " ) ;
if ( hDbgHelp )
fnMiniDumpWriteDump = ( MINIDUMPWRITEDUMP ) GetProcAddress ( hDbgHelp , " MiniDumpWriteDump " ) ;
else
fnMiniDumpWriteDump = NULL ;
if ( fnMiniDumpWriteDump )
{
if ( MessageBox ( NULL , " KABOOM! We crashed! \n Blame the monkey in the corner. \n I hope you saved your work. \n Would you like to take a dump now? " , DISTRIBUTION " Sucks " , MB_ICONSTOP | MB_YESNO ) ! = IDYES )
2013-03-12 23:24:15 +00:00
{
if ( pIsDebuggerPresent ( ) )
{
//its possible someone attached a debugger while we were showing that message
return EXCEPTION_CONTINUE_SEARCH ;
}
2010-07-18 08:42:59 +00:00
return EXCEPTION_EXECUTE_HANDLER ;
2013-03-12 23:24:15 +00:00
}
2010-07-18 08:42:59 +00:00
/*take a dump*/
GetTempPath ( sizeof ( dumpPath ) - 16 , dumpPath ) ;
Q_strncatz ( dumpPath , DISTRIBUTION " CrashDump.dmp " , sizeof ( dumpPath ) ) ;
dumpfile = CreateFile ( dumpPath , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( dumpfile )
{
MINIDUMP_EXCEPTION_INFORMATION crashinfo ;
crashinfo . ClientPointers = TRUE ;
crashinfo . ExceptionPointers = exceptionInfo ;
crashinfo . ThreadId = GetCurrentThreadId ( ) ;
if ( fnMiniDumpWriteDump ( hProc , procid , dumpfile , MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithDataSegs , & crashinfo , NULL , NULL ) )
{
CloseHandle ( dumpfile ) ;
MessageBox ( NULL , va ( " You can find the crashdump at \n %s \n Please send this file to someone. \n \n Warning: sensitive information (like your current user name) might be present in the dump. \n You will probably want to compress it. " , dumpPath ) , DISTRIBUTION " Sucks " , 0 ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
}
}
else
MessageBox ( NULL , " Kaboom! Sorry. No MiniDumpWriteDump function. " , DISTRIBUTION " Sucks " , 0 ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
# endif
2009-03-07 05:05:54 +00:00
void Sys_CloseLibrary ( dllhandle_t * lib )
{
FreeLibrary ( ( HMODULE ) lib ) ;
}
2009-11-04 21:16:50 +00:00
dllhandle_t * Sys_LoadLibrary ( const char * name , dllfunction_t * funcs )
2009-03-07 05:05:54 +00:00
{
int i ;
HMODULE lib ;
lib = LoadLibrary ( name ) ;
if ( ! lib )
return NULL ;
2011-05-30 21:48:32 +00:00
if ( funcs )
2009-03-07 05:05:54 +00:00
{
2011-05-30 21:48:32 +00:00
for ( i = 0 ; funcs [ i ] . name ; i + + )
{
* funcs [ i ] . funcptr = GetProcAddress ( lib , funcs [ i ] . name ) ;
if ( ! * funcs [ i ] . funcptr )
break ;
}
if ( funcs [ i ] . name )
{
Sys_CloseLibrary ( ( dllhandle_t * ) lib ) ;
lib = NULL ;
}
2009-03-07 05:05:54 +00:00
}
return ( dllhandle_t * ) lib ;
}
2009-11-04 21:16:50 +00:00
void * Sys_GetAddressForName ( dllhandle_t * module , const char * exportname )
2009-03-07 05:05:54 +00:00
{
if ( ! module )
return NULL ;
return GetProcAddress ( ( HINSTANCE ) module , exportname ) ;
}
# ifdef HLSERVER
char * Sys_GetNameForAddress ( dllhandle_t * module , void * address )
{
//windows doesn't provide a function to do this, so we have to do it ourselves.
//this isn't the fastest way...
//halflife needs this function.
char * base = ( char * ) module ;
IMAGE_DATA_DIRECTORY * datadir ;
IMAGE_EXPORT_DIRECTORY * block ;
IMAGE_NT_HEADERS * ntheader ;
IMAGE_DOS_HEADER * dosheader = ( void * ) base ;
int i , j ;
DWORD * funclist ;
DWORD * namelist ;
SHORT * ordilist ;
if ( ! dosheader | | dosheader - > e_magic ! = IMAGE_DOS_SIGNATURE )
return NULL ; //yeah, that wasn't an exe
ntheader = ( void * ) ( base + dosheader - > e_lfanew ) ;
if ( ! dosheader - > e_lfanew | | ntheader - > Signature ! = IMAGE_NT_SIGNATURE )
return NULL ; //urm, wait, a 16bit dos exe?
datadir = & ntheader - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_EXPORT ] ;
2010-12-15 12:29:58 +00:00
2009-03-07 05:05:54 +00:00
block = ( IMAGE_EXPORT_DIRECTORY * ) ( base + datadir - > VirtualAddress ) ;
funclist = ( DWORD * ) ( base + block - > AddressOfFunctions ) ;
namelist = ( DWORD * ) ( base + block - > AddressOfNames ) ;
ordilist = ( SHORT * ) ( base + block - > AddressOfNameOrdinals ) ;
for ( i = 0 ; i < block - > NumberOfFunctions ; i + + )
{
if ( base + funclist [ i ] = = address )
{
for ( j = 0 ; j < block - > NumberOfNames ; j + + )
{
if ( ordilist [ j ] = = i )
{
return base + namelist [ i ] ;
}
}
//it has no name. huh?
return NULL ;
}
}
return NULL ;
}
# endif
2004-12-13 00:44:43 +00:00
2004-08-23 00:15:46 +00:00
# include <fcntl.h>
# include <io.h>
# include <signal.h>
# include <shellapi.h>
# ifdef USESERVICE
qboolean asservice ;
2010-12-15 12:29:58 +00:00
SERVICE_STATUS_HANDLE ServerServiceStatusHandle ;
SERVICE_STATUS MyServiceStatus ;
2004-08-23 00:15:46 +00:00
void CreateSampleService ( qboolean create ) ;
# endif
void PR_Deinit ( void ) ;
cvar_t sys_nostdout = { " sys_nostdout " , " 0 " } ;
2005-10-04 21:16:47 +00:00
cvar_t sys_colorconsole = { " sys_colorconsole " , " 1 " } ;
2004-08-23 00:15:46 +00:00
HWND consolewindowhandle ;
HWND hiddenwindowhandler ;
2005-12-06 01:38:31 +00:00
int Sys_DebugLog ( char * file , char * fmt , . . . )
2004-08-23 00:15:46 +00:00
{
2010-12-15 12:29:58 +00:00
va_list argptr ;
2004-08-23 00:15:46 +00:00
static char data [ 1024 ] ;
int fd ;
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
va_start ( argptr , fmt ) ;
2006-03-11 04:39:16 +00:00
vsnprintf ( data , sizeof ( data ) - 1 , fmt , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
fd = open ( file , O_WRONLY | O_CREAT | O_APPEND , 0666 ) ;
2005-12-05 16:47:29 +00:00
if ( fd )
{
write ( fd , data , strlen ( data ) ) ;
close ( fd ) ;
return 0 ;
}
return 1 ; // error
2004-08-23 00:15:46 +00:00
} ;
/*
= = = = = = = = = = = = = = = =
Sys_FileTime
= = = = = = = = = = = = = = = =
*/
int Sys_FileTime ( char * path )
{
FILE * f ;
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
f = fopen ( path , " rb " ) ;
if ( f )
{
fclose ( f ) ;
return 1 ;
}
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
return - 1 ;
}
/*
= = = = = = = = = = = = = = = =
Sys_mkdir
= = = = = = = = = = = = = = = =
*/
int _mkdir ( const char * path ) ; ;
void Sys_mkdir ( char * path )
{
_mkdir ( path ) ;
}
qboolean Sys_remove ( char * path )
{
remove ( path ) ;
return true ;
}
2012-04-24 07:59:11 +00:00
qboolean Sys_Rename ( char * oldfname , char * newfname )
{
return ! rename ( oldfname , newfname ) ;
}
2004-08-23 00:15:46 +00:00
2013-06-29 16:01:07 +00:00
int Sys_EnumerateFiles ( const char * gpath , const char * match , int ( * func ) ( const char * fname , int fsize , void * parm , searchpathfuncs_t * spath ) , void * parm , searchpathfuncs_t * spath )
2004-08-23 00:15:46 +00:00
{
HANDLE r ;
2010-12-15 12:29:58 +00:00
WIN32_FIND_DATA fd ;
2004-08-23 00:15:46 +00:00
char apath [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
char * s ;
int go ;
2006-05-19 19:15:52 +00:00
Q_strncpyz ( apath , match , sizeof ( apath ) ) ;
2004-08-23 00:15:46 +00:00
// sprintf(apath, "%s%s", gpath, match);
for ( s = apath + strlen ( apath ) - 1 ; s > = apath ; s - - )
{
2010-12-15 12:29:58 +00:00
if ( * s = = ' / ' )
2004-08-23 00:15:46 +00:00
break ;
}
s + + ;
2010-12-15 12:29:58 +00:00
* s = ' \0 ' ;
2004-08-23 00:15:46 +00:00
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s/%s " , gpath , match ) ;
2004-08-23 00:15:46 +00:00
r = FindFirstFile ( file , & fd ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
2005-05-30 12:30:41 +00:00
if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
2004-08-23 00:15:46 +00:00
{
if ( * fd . cFileName ! = ' . ' )
{
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , apath , fd . cFileName ) ;
2013-03-31 04:21:08 +00:00
go = func ( file , fd . nFileSizeLow , parm , spath ) ;
2004-08-23 00:15:46 +00:00
}
}
2005-05-30 12:30:41 +00:00
else
{
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s " , apath , fd . cFileName ) ;
2013-03-31 04:21:08 +00:00
go = func ( file , fd . nFileSizeLow , parm , spath ) ;
2005-05-30 12:30:41 +00:00
}
2004-08-23 00:15:46 +00:00
}
while ( FindNextFile ( r , & fd ) & & go ) ;
FindClose ( r ) ;
return go ;
}
/*
= = = = = = = = = = = = = = = =
Sys_Error
= = = = = = = = = = = = = = = =
*/
# include <process.h>
void Sys_Error ( const char * error , . . . )
{
va_list argptr ;
char text [ 1024 ] ;
double end ;
2006-05-13 21:11:06 +00:00
STARTUPINFO startupinfo ;
PROCESS_INFORMATION processinfo ;
2004-08-23 00:15:46 +00:00
va_start ( argptr , error ) ;
2006-03-11 04:39:16 +00:00
vsnprintf ( text , sizeof ( text ) - 1 , error , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
// MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
Sys_Printf ( " ERROR: %s \n " , text ) ;
2005-09-26 08:07:26 +00:00
Con_Log ( text ) ;
2004-08-23 00:15:46 +00:00
NET_Shutdown ( ) ; //free sockets and stuff.
# ifdef USESERVICE
if ( asservice )
Sys_Quit ( ) ;
# endif
2006-01-02 22:36:12 +00:00
if ( COM_CheckParm ( " -noreset " ) )
Sys_Quit ( ) ;
2004-08-23 00:15:46 +00:00
Sys_Printf ( " A new server will be started in 10 seconds unless you press a key \n " ) ;
//check for a key press, quitting if we get one in 10 secs
end = Sys_DoubleTime ( ) + 10 ;
while ( Sys_DoubleTime ( ) < end )
{
2006-05-13 21:11:06 +00:00
Sleep ( 500 ) ; // don't burn up CPU with polling
2004-08-23 00:15:46 +00:00
if ( _kbhit ( ) )
Sys_Quit ( ) ;
}
2006-05-13 21:11:06 +00:00
Sys_Printf ( " \n Loading new instance of FTE... \n \n \n " ) ;
2004-08-23 00:15:46 +00:00
PR_Deinit ( ) ; //this takes a bit more mem
Rank_Flush ( ) ;
# ifndef MINGW
fcloseall ( ) ; //make sure all files are written.
# endif
2013-07-14 12:22:51 +00:00
2004-08-23 00:15:46 +00:00
// system("dqwsv.exe"); //spawn a new server to take over. This way, if debugging, then any key will quit, otherwise the server will just spawn a new one.
2006-05-13 21:11:06 +00:00
memset ( & startupinfo , 0 , sizeof ( startupinfo ) ) ;
memset ( & processinfo , 0 , sizeof ( processinfo ) ) ;
CreateProcess ( NULL ,
GetCommandLine ( ) ,
NULL ,
NULL ,
false ,
0 ,
NULL ,
NULL ,
& startupinfo ,
& processinfo ) ;
CloseHandle ( processinfo . hProcess ) ;
CloseHandle ( processinfo . hThread ) ;
2004-08-23 00:15:46 +00:00
Sys_Quit ( ) ;
2011-05-19 13:34:07 +00:00
exit ( 1 ) ; // this function is NORETURN type, complains without this
2004-08-23 00:15:46 +00:00
}
2007-10-02 15:17:22 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Milliseconds
= = = = = = = = = = = = = = = =
*/
unsigned int Sys_Milliseconds ( void )
{
static DWORD starttime ;
static qboolean first = true ;
DWORD now ;
// double t;
now = timeGetTime ( ) ;
if ( first ) {
first = false ;
starttime = now ;
return 0.0 ;
}
/*
if ( now < starttime ) // wrapped?
{
double r ;
r = ( now ) + ( LONG_MAX - starttime ) ;
starttime = now ;
return r ;
}
if ( now - starttime = = 0 )
return 0.0 ;
*/
return ( now - starttime ) ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_DoubleTime
= = = = = = = = = = = = = = = =
*/
double Sys_DoubleTime ( void )
{
double t ;
struct _timeb tstruct ;
static int starttime ;
_ftime ( & tstruct ) ;
2006-09-17 00:59:22 +00:00
2004-08-23 00:15:46 +00:00
if ( ! starttime )
starttime = tstruct . time ;
t = ( tstruct . time - starttime ) + tstruct . millitm * 0.001 ;
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
return t ;
}
/*
= = = = = = = = = = = = = = = =
Sys_ConsoleInput
= = = = = = = = = = = = = = = =
*/
2005-10-04 21:16:47 +00:00
char coninput_text [ 256 ] ;
int coninput_len ;
2004-08-23 00:15:46 +00:00
char * Sys_ConsoleInput ( void )
{
int c ;
if ( consolewindowhandle )
{
MSG msg ;
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_NOREMOVE ) )
{
if ( ! GetMessage ( & msg , NULL , 0 , 0 ) )
return NULL ;
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return NULL ;
}
// read a line out
while ( _kbhit ( ) )
{
c = _getch ( ) ;
if ( c = = ' \r ' )
{
2005-10-04 21:16:47 +00:00
coninput_text [ coninput_len ] = 0 ;
2004-08-23 00:15:46 +00:00
putch ( ' \n ' ) ;
2005-10-04 21:16:47 +00:00
putch ( ' ] ' ) ;
coninput_len = 0 ;
return coninput_text ;
2004-08-23 00:15:46 +00:00
}
if ( c = = 8 )
{
2005-10-04 21:16:47 +00:00
if ( coninput_len )
2004-08-23 00:15:46 +00:00
{
2005-10-04 21:16:47 +00:00
putch ( c ) ;
2004-08-23 00:15:46 +00:00
putch ( ' ' ) ;
putch ( c ) ;
2005-10-04 21:16:47 +00:00
coninput_len - - ;
coninput_text [ coninput_len ] = 0 ;
}
continue ;
}
if ( c = = ' \t ' )
{
int i ;
2012-11-27 03:23:19 +00:00
char * s = Cmd_CompleteCommand ( coninput_text , true , true , 0 , NULL ) ;
2005-10-04 21:16:47 +00:00
if ( s )
{
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
strcpy ( coninput_text , s ) ;
coninput_len = strlen ( coninput_text ) ;
printf ( " %s " , coninput_text ) ;
2004-08-23 00:15:46 +00:00
}
continue ;
}
2005-10-04 21:16:47 +00:00
putch ( c ) ;
coninput_text [ coninput_len ] = c ;
coninput_len + + ;
coninput_text [ coninput_len ] = 0 ;
if ( coninput_len = = sizeof ( coninput_text ) )
coninput_len = 0 ;
2004-08-23 00:15:46 +00:00
}
return NULL ;
}
2005-10-04 21:16:47 +00:00
void ApplyColour ( unsigned int chr )
{
2006-01-01 09:01:15 +00:00
static int oldchar = CON_WHITEMASK ;
chr & = CON_FLAGSMASK ;
2005-10-04 21:16:47 +00:00
if ( oldchar = = chr )
return ;
oldchar = chr ;
if ( hconsoleout )
{
2006-01-01 09:01:15 +00:00
unsigned short val = 0 ;
2010-12-15 12:29:58 +00:00
// bits 28-31 of the console chars match up to the attributes for
2006-01-01 09:01:15 +00:00
// the CHAR_INFO struct exactly
if ( chr & CON_NONCLEARBG )
2006-07-29 21:09:43 +00:00
val = ( ( chr & ( CON_FGMASK | CON_BGMASK ) ) > > CON_FGSHIFT ) ;
2006-01-01 09:01:15 +00:00
else
2005-10-04 21:16:47 +00:00
{
2006-01-01 09:01:15 +00:00
int fg = ( chr & CON_FGMASK ) > > CON_FGSHIFT ;
switch ( fg )
{
case COLOR_BLACK : // reverse ^0 like the Linux version
val = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE ;
break ;
case COLOR_WHITE : // reset to defaults?
val = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE ; // use grey
break ;
case COLOR_GREY :
val = FOREGROUND_INTENSITY ; // color light grey as dark grey
break ;
default :
val = fg ; // send RGBI value as is
break ;
}
2005-10-04 21:16:47 +00:00
}
2006-01-01 09:01:15 +00:00
if ( ( chr & CON_HALFALPHA ) & & ( val & ~ FOREGROUND_INTENSITY ) )
val & = ~ FOREGROUND_INTENSITY ; // strip intensity to fake alpha
2005-10-04 21:16:47 +00:00
SetConsoleTextAttribute ( hconsoleout , val ) ;
}
}
void Sys_PrintColouredChar ( unsigned int chr )
{
2013-03-31 04:21:08 +00:00
DWORD dummy ;
wchar_t wc ;
2012-11-27 03:23:19 +00:00
if ( chr & CON_HIDDEN )
return ;
2005-10-04 21:16:47 +00:00
ApplyColour ( chr ) ;
2013-03-31 04:21:08 +00:00
wc = chr & CON_CHARMASK ;
WriteConsoleW ( hconsoleout , & wc , 1 , & dummy , NULL ) ;
2005-10-04 21:16:47 +00:00
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Printf
= = = = = = = = = = = = = = = =
*/
2005-10-04 21:16:47 +00:00
# define MAXPRINTMSG 4096
2004-08-23 00:15:46 +00:00
void Sys_Printf ( char * fmt , . . . )
{
2010-12-15 12:29:58 +00:00
va_list argptr ;
2004-08-23 00:15:46 +00:00
if ( sys_nostdout . value )
return ;
2005-10-04 21:16:47 +00:00
if ( 1 )
{
char msg [ MAXPRINTMSG ] ;
unsigned char * t ;
va_start ( argptr , fmt ) ;
2006-03-11 04:39:16 +00:00
vsnprintf ( msg , sizeof ( msg ) - 1 , fmt , argptr ) ;
2005-10-04 21:16:47 +00:00
va_end ( argptr ) ;
{
int i ;
2010-12-15 12:29:58 +00:00
2005-10-04 21:16:47 +00:00
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
putch ( ' \b ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' ' ) ;
putch ( ' ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
putch ( ' \b ' ) ;
}
if ( sys_colorconsole . value & & hconsoleout )
{
2012-11-27 03:23:19 +00:00
conchar_t out [ MAXPRINTMSG ] , * c , * end ;
end = COM_ParseFunString ( CON_WHITEMASK , msg , out , sizeof ( out ) , false ) ;
for ( c = out ; c < end ; c + + )
Sys_PrintColouredChar ( * c ) ;
2005-10-04 21:16:47 +00:00
2006-01-01 09:01:15 +00:00
ApplyColour ( CON_WHITEMASK ) ;
2005-10-04 21:16:47 +00:00
}
else
2012-11-27 03:23:19 +00:00
{
for ( t = ( unsigned char * ) msg ; * t ; t + + )
{
if ( * t > = 146 & & * t < 156 )
* t = * t - 146 + ' 0 ' ;
if ( * t > = 0x12 & & * t < = 0x1b )
* t = * t - 0x12 + ' 0 ' ;
if ( * t = = 143 )
* t = ' . ' ;
if ( * t = = 157 | | * t = = 158 | | * t = = 159 )
* t = ' - ' ;
if ( * t > = 128 )
* t - = 128 ;
if ( * t = = 16 )
* t = ' [ ' ;
if ( * t = = 17 )
* t = ' ] ' ;
if ( * t = = 0x1c )
* t = 249 ;
}
2005-10-04 21:16:47 +00:00
printf ( " %s " , msg ) ;
2012-11-27 03:23:19 +00:00
}
2005-10-04 21:16:47 +00:00
if ( coninput_len )
printf ( " ]%s " , coninput_text ) ;
else
putch ( ' ] ' ) ;
}
else
{
va_start ( argptr , fmt ) ;
vprintf ( fmt , argptr ) ;
va_end ( argptr ) ;
}
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = =
Sys_Quit
= = = = = = = = = = = = = = = =
*/
void Sys_Quit ( void )
{
# ifdef USESERVICE
if ( asservice )
{
2010-12-15 12:29:58 +00:00
MyServiceStatus . dwCurrentState = SERVICE_STOPPED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
2004-08-23 00:15:46 +00:00
2010-12-15 12:29:58 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
2004-08-23 00:15:46 +00:00
}
# endif
exit ( 0 ) ;
}
int restorecode ;
LRESULT ( CALLBACK Sys_WindowHandler ) ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
if ( uMsg = = WM_USER )
{
if ( lParam & 1 )
{
}
else if ( ( lParam & 2 & & restorecode = = 0 ) | |
( lParam & 4 & & restorecode = = 1 ) | |
( lParam & 4 & & restorecode = = 2 ) )
{
// MessageBox(NULL, "Hello", "", 0);
restorecode + + ;
}
else if ( lParam & 2 & & restorecode = = 3 )
{
DestroyWindow ( hWnd ) ;
ShowWindow ( consolewindowhandle , SW_SHOWNORMAL ) ;
consolewindowhandle = NULL ;
Cbuf_AddText ( " status \n " , RESTRICT_LOCAL ) ;
}
else if ( lParam & 6 )
{
restorecode = ( lParam & 2 ) > 0 ;
}
return 0 ;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
void Sys_HideConsole ( void )
{
HMODULE kernel32dll ;
HWND ( WINAPI * GetConsoleWindow ) ( void ) ;
if ( consolewindowhandle )
return ; //err... already hidden... ?
restorecode = 0 ;
GetConsoleWindow = NULL ;
kernel32dll = LoadLibrary ( " kernel32.dll " ) ;
consolewindowhandle = NULL ;
if ( kernel32dll )
{
GetConsoleWindow = ( void * ) GetProcAddress ( kernel32dll , " GetConsoleWindow " ) ;
if ( GetConsoleWindow )
consolewindowhandle = GetConsoleWindow ( ) ;
FreeModule ( kernel32dll ) ; //works because the underlying code uses kernel32, so this decreases the reference count rather than closing it.
}
if ( ! consolewindowhandle )
{
char old [ 512 ] ;
2005-03-10 03:55:18 +00:00
# define STRINGH "Trying to hide" //msvc sucks
2004-08-23 00:15:46 +00:00
GetConsoleTitle ( old , sizeof ( old ) ) ;
2005-03-10 03:55:18 +00:00
SetConsoleTitle ( STRINGH ) ;
consolewindowhandle = FindWindow ( NULL , STRINGH ) ;
2004-08-23 00:15:46 +00:00
SetConsoleTitle ( old ) ;
2005-03-10 03:55:18 +00:00
# undef STRINGH
2004-08-23 00:15:46 +00:00
}
if ( consolewindowhandle )
{
WNDCLASS wc ;
NOTIFYICONDATA d ;
/* Register the frame class */
memset ( & wc , 0 , sizeof ( wc ) ) ;
wc . style = 0 ;
wc . lpfnWndProc = Sys_WindowHandler ;
wc . cbClsExtra = 0 ;
wc . cbWndExtra = 0 ;
wc . hInstance = GetModuleHandle ( NULL ) ;
wc . hIcon = 0 ;
wc . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
wc . hbrBackground = NULL ;
wc . lpszMenuName = 0 ;
wc . lpszClassName = " DeadQuake " ;
RegisterClass ( & wc ) ;
hiddenwindowhandler = CreateWindow ( wc . lpszClassName , " DeadQuake " , 0 , 0 , 0 , 16 , 16 , NULL , NULL , GetModuleHandle ( NULL ) , NULL ) ;
if ( ! hiddenwindowhandler )
{
Con_Printf ( " Failed to create window \n " ) ;
return ;
}
ShowWindow ( consolewindowhandle , SW_HIDE ) ;
d . cbSize = sizeof ( NOTIFYICONDATA ) ;
d . hWnd = hiddenwindowhandler ;
d . uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE ;
d . hIcon = NULL ;
d . uCallbackMessage = WM_USER ;
d . uID = 0 ;
strcpy ( d . szTip , " " ) ;
Shell_NotifyIcon ( NIM_ADD , & d ) ;
}
else
Con_Printf ( " Your OS doesn't seem to properly support the way this was implemented \n " ) ;
}
void Sys_ServerActivity ( void )
{
HMODULE kernel32dll ;
HWND ( WINAPI * GetConsoleWindow ) ( void ) ;
HWND wnd ;
restorecode = 0 ;
GetConsoleWindow = NULL ;
kernel32dll = LoadLibrary ( " kernel32.dll " ) ;
wnd = NULL ;
if ( kernel32dll )
{
GetConsoleWindow = ( void * ) GetProcAddress ( kernel32dll , " GetConsoleWindow " ) ;
if ( GetConsoleWindow )
wnd = GetConsoleWindow ( ) ;
FreeModule ( kernel32dll ) ; //works because the underlying code uses kernel32, so this decreases the reference count rather than closing it.
}
if ( ! wnd )
{
char old [ 512 ] ;
2005-03-10 03:55:18 +00:00
# define STRINGF "About To Flash" //msvc sucks
2004-08-23 00:15:46 +00:00
GetConsoleTitle ( old , sizeof ( old ) ) ;
2005-03-10 03:55:18 +00:00
SetConsoleTitle ( STRINGF ) ;
wnd = FindWindow ( NULL , STRINGF ) ;
2004-08-23 00:15:46 +00:00
SetConsoleTitle ( old ) ;
2005-03-10 03:55:18 +00:00
# undef STRINGF
2004-08-23 00:15:46 +00:00
}
2009-04-18 23:48:35 +00:00
if ( wnd & & GetActiveWindow ( ) ! = wnd )
2004-08-23 00:15:46 +00:00
FlashWindow ( wnd , true ) ;
}
/*
= = = = = = = = = = = = =
Sys_Init
Quake calls this so the system can register variables before host_hunklevel
is marked
= = = = = = = = = = = = =
*/
void Sys_Init ( void )
{
Cvar_Register ( & sys_nostdout , " System controls " ) ;
2005-10-04 21:16:47 +00:00
Cvar_Register ( & sys_colorconsole , " System controls " ) ;
2004-08-23 00:15:46 +00:00
Cmd_AddCommand ( " hide " , Sys_HideConsole ) ;
2005-10-04 21:16:47 +00:00
hconsoleout = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
2013-03-31 04:21:08 +00:00
// SetConsoleCP(CP_UTF8);
// SetConsoleOutputCP(CP_UTF8);
2004-08-23 00:15:46 +00:00
}
2011-04-30 17:21:10 +00:00
void Sys_Shutdown ( void )
{
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = =
main
= = = = = = = = = = = = = = = = = =
*/
char * newargv [ 256 ] ;
void Signal_Error_Handler ( int sig )
{
Sys_Error ( " Illegal error occured " ) ;
}
void StartQuakeServer ( void )
{
quakeparms_t parms ;
2013-10-08 14:28:11 +00:00
static char bindir [ MAX_OSPATH ] ;
2004-08-23 00:15:46 +00:00
2012-11-27 03:23:19 +00:00
memset ( & parms , 0 , sizeof ( parms ) ) ;
2004-08-23 00:15:46 +00:00
TL_InitLanguages ( ) ;
parms . argc = com_argc ;
parms . argv = com_argv ;
2013-05-11 14:02:55 +00:00
GetModuleFileName ( NULL , bindir , sizeof ( bindir ) - 1 ) ;
* COM_SkipPath ( bindir ) = 0 ;
parms . binarydir = bindir ;
2013-11-21 23:02:28 +00:00
parms . basedir = " ./ " ;
2004-08-23 00:15:46 +00:00
SV_Init ( & parms ) ;
// run one frame immediately for first heartbeat
2010-12-15 12:29:58 +00:00
SV_Frame ( ) ;
2004-08-23 00:15:46 +00:00
}
# ifdef USESERVICE
int servicecontrol ;
# endif
void ServerMainLoop ( void )
{
double newtime , time , oldtime ;
2011-06-05 23:53:33 +00:00
int delay = 1 ;
2004-08-23 00:15:46 +00:00
//
// main loop
//
oldtime = Sys_DoubleTime ( ) - 0.1 ;
while ( 1 )
{
2011-06-05 23:53:33 +00:00
NET_Sleep ( delay , false ) ;
2004-08-23 00:15:46 +00:00
// find time passed since last cycle
newtime = Sys_DoubleTime ( ) ;
time = newtime - oldtime ;
oldtime = newtime ;
2011-06-05 23:53:33 +00:00
delay = SV_Frame ( ) * 1000 ;
2004-08-23 00:15:46 +00:00
# ifdef USESERVICE
switch ( servicecontrol )
{
case SERVICE_CONTROL_PAUSE :
2010-12-15 12:29:58 +00:00
// Initialization complete - report running status.
MyServiceStatus . dwCurrentState = SERVICE_PAUSED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
2004-08-23 00:15:46 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
sv . paused | = 2 ;
break ;
case SERVICE_CONTROL_CONTINUE :
2010-12-15 12:29:58 +00:00
// Initialization complete - report running status.
MyServiceStatus . dwCurrentState = SERVICE_RUNNING ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
2004-08-23 00:15:46 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
sv . paused & = ~ 2 ;
break ;
case SERVICE_CONTROL_STOP : //leave the loop
return ;
default :
break ;
}
# endif
}
}
# ifdef USESERVICE
VOID WINAPI MyServiceCtrlHandler ( DWORD dwControl )
{
servicecontrol = dwControl ;
}
void WINAPI StartQuakeServerService ( DWORD argc , LPTSTR * argv )
{
HKEY hk ;
char path [ MAX_OSPATH ] ;
DWORD pathlen ;
DWORD type ;
asservice = true ;
2010-12-15 12:29:58 +00:00
MyServiceStatus . dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS ;
MyServiceStatus . dwCurrentState = SERVICE_START_PENDING ;
MyServiceStatus . dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
ServerServiceStatusHandle = RegisterServiceCtrlHandler (
SERVICENAME ,
MyServiceCtrlHandler ) ;
if ( ServerServiceStatusHandle = = ( SERVICE_STATUS_HANDLE ) 0 )
{
printf ( " [MY_SERVICE] RegisterServiceCtrlHandler failed %d \n " , GetLastError ( ) ) ;
return ;
2004-11-13 17:39:26 +00:00
}
2004-08-23 00:15:46 +00:00
2008-09-11 03:39:34 +00:00
RegOpenKey ( HKEY_LOCAL_MACHINE , " Software \\ " DISTRIBUTIONLONG " \\ " FULLENGINENAME , & hk ) ;
2004-08-23 00:15:46 +00:00
RegQueryValueEx ( hk , " servicepath " , 0 , & type , NULL , & pathlen ) ;
if ( type = = REG_SZ & & pathlen < sizeof ( path ) )
RegQueryValueEx ( hk , " servicepath " , 0 , NULL , path , & pathlen ) ;
RegCloseKey ( hk ) ;
SetCurrentDirectory ( path ) ;
COM_InitArgv ( argc , argv ) ;
StartQuakeServer ( ) ;
2010-12-15 12:29:58 +00:00
// Handle error condition
2004-08-23 00:15:46 +00:00
if ( ! sv . state )
2010-12-15 12:29:58 +00:00
{
MyServiceStatus . dwCurrentState = SERVICE_STOPPED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
return ;
}
// Initialization complete - report running status.
MyServiceStatus . dwCurrentState = SERVICE_RUNNING ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
if ( ! SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) )
{
printf ( " [MY_SERVICE] SetServiceStatus error %ld \n " , GetLastError ( ) ) ;
}
2004-08-23 00:15:46 +00:00
ServerMainLoop ( ) ;
2010-12-15 12:29:58 +00:00
MyServiceStatus . dwCurrentState = SERVICE_STOPPED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
2004-08-23 00:15:46 +00:00
2010-12-15 12:29:58 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
2004-08-23 00:15:46 +00:00
2010-12-15 12:29:58 +00:00
return ;
2004-08-23 00:15:46 +00:00
}
2010-12-15 12:29:58 +00:00
SERVICE_TABLE_ENTRY DispatchTable [ ] =
{
{ SERVICENAME , StartQuakeServerService } ,
{ NULL , NULL }
} ;
2004-08-23 00:15:46 +00:00
# endif
qboolean NET_Sleep ( int msec , qboolean stdinissocket ) ;
int main ( int argc , char * * argv )
{
# ifdef USESERVICE
2010-12-15 12:29:58 +00:00
if ( StartServiceCtrlDispatcher ( DispatchTable ) )
{
2004-08-23 00:15:46 +00:00
return true ;
}
# endif
2010-07-18 08:42:59 +00:00
# ifdef CATCHCRASH
__try
2004-08-23 00:15:46 +00:00
# endif
2010-07-18 08:42:59 +00:00
{
2011-05-19 13:34:07 +00:00
COM_InitArgv ( argc , ( const char * * ) argv ) ;
2010-07-18 08:42:59 +00:00
# ifdef USESERVICE
if ( COM_CheckParm ( " -register " ) )
{
CreateSampleService ( 1 ) ;
return true ;
}
if ( COM_CheckParm ( " -unregister " ) )
{
CreateSampleService ( 0 ) ;
return true ;
}
# endif
2004-11-13 17:39:26 +00:00
2010-07-18 08:42:59 +00:00
# ifndef _DEBUG
if ( COM_CheckParm ( " -noreset " ) )
{
signal ( SIGFPE , Signal_Error_Handler ) ;
signal ( SIGILL , Signal_Error_Handler ) ;
signal ( SIGSEGV , Signal_Error_Handler ) ;
}
# endif
StartQuakeServer ( ) ;
ServerMainLoop ( ) ;
}
# ifdef CATCHCRASH
__except ( CrashExceptionHandler ( GetExceptionCode ( ) , GetExceptionInformation ( ) ) )
2004-11-13 17:39:26 +00:00
{
2010-07-18 08:42:59 +00:00
return 1 ;
2004-11-13 17:39:26 +00:00
}
# endif
2004-08-23 00:15:46 +00:00
return true ;
}
# ifdef USESERVICE
2010-12-15 12:29:58 +00:00
void CreateSampleService ( qboolean create )
{
2004-08-23 00:15:46 +00:00
BOOL deleted ;
char path [ MAX_OSPATH ] ;
char exe [ MAX_OSPATH ] ;
SC_HANDLE schService ;
SC_HANDLE schSCManager ;
2010-12-15 12:29:58 +00:00
// Open a handle to the SC Manager database.
schSCManager = OpenSCManager (
NULL , // local machine
NULL , // ServicesActive database
SC_MANAGER_ALL_ACCESS ) ; // full access rights
if ( NULL = = schSCManager )
2004-08-23 00:15:46 +00:00
{
Con_Printf ( " Failed to open SCManager (%d) \n " , GetLastError ( ) ) ;
return ;
}
if ( ! GetModuleFileName ( NULL , exe + 1 , sizeof ( exe ) - 2 ) )
{
Con_Printf ( " Path too long \n " ) ;
return ;
}
GetCurrentDirectory ( sizeof ( path ) , path ) ;
exe [ 0 ] = ' \" ' ;
exe [ strlen ( path ) + 1 ] = ' \0 ' ;
exe [ strlen ( path ) ] = ' \" ' ;
if ( ! create )
{
schService = OpenServiceA ( schSCManager , SERVICENAME , SERVICE_ALL_ACCESS ) ;
if ( schService )
{
deleted = DeleteService ( schService ) ;
}
}
else
{
HKEY hk ;
2008-09-11 03:39:34 +00:00
RegOpenKey ( HKEY_LOCAL_MACHINE , " Software \\ " DISTRIBUTIONLONG " \\ " FULLENGINENAME , & hk ) ;
if ( ! hk ) RegCreateKey ( HKEY_LOCAL_MACHINE , " Software \\ " DISTRIBUTIONLONG " \\ " FULLENGINENAME , & hk ) ;
2004-08-23 00:15:46 +00:00
RegSetValueEx ( hk , " servicepath " , 0 , REG_SZ , path , strlen ( path ) ) ;
RegCloseKey ( hk ) ;
2010-12-15 12:29:58 +00:00
schService = CreateService (
schSCManager , // SCManager database
SERVICENAME , // name of service
FULLENGINENAME " Server " , // service name to display
SERVICE_ALL_ACCESS , // desired access
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS , // service type
SERVICE_AUTO_START , // start type
SERVICE_ERROR_NORMAL , // error control type
exe , // service's binary
NULL , // no load ordering group
NULL , // no tag identifier
NULL , // no dependencies
NULL , // LocalSystem account
NULL ) ; // no password
2004-08-23 00:15:46 +00:00
}
2010-12-15 12:29:58 +00:00
if ( schService = = NULL )
2004-08-23 00:15:46 +00:00
{
2010-12-15 12:29:58 +00:00
Con_Printf ( " CreateService failed. \n " ) ;
2004-08-23 00:15:46 +00:00
return ;
}
else
{
2010-12-15 12:29:58 +00:00
CloseServiceHandle ( schService ) ;
2004-08-23 00:15:46 +00:00
return ;
}
}
2004-09-04 17:59:22 +00:00
# endif
2007-12-30 00:09:34 +00:00
2011-07-06 01:01:13 +00:00
void Sys_Sleep ( double seconds )
2011-07-03 16:24:53 +00:00
{
2011-07-06 01:01:13 +00:00
Sleep ( seconds * 1000 ) ;
2011-07-03 16:24:53 +00:00
}
2013-03-31 04:21:08 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_RandomBytes
= = = = = = = = = = = = = = = =
*/
# include <wincrypt.h>
qboolean Sys_RandomBytes ( qbyte * string , int len )
{
HCRYPTPROV prov ;
if ( ! CryptAcquireContext ( & prov , NULL , NULL , PROV_RSA_FULL , CRYPT_VERIFYCONTEXT ) )
{
return false ;
}
if ( ! CryptGenRandom ( prov , len , ( BYTE * ) string ) )
{
CryptReleaseContext ( prov , 0 ) ;
return false ;
}
CryptReleaseContext ( prov , 0 ) ;
return true ;
}
2007-12-30 00:09:34 +00:00
# endif