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
2013-11-21 23:16:59 +00:00
qboolean WinNT ; //if true, use utf-16 file paths. if false, hope that paths are in ascii.
2009-03-07 05:05:54 +00:00
2014-09-02 02:44:43 +00:00
# if defined(_DEBUG) || defined(DEBUG)
2010-07-18 08:42:59 +00:00
# define CATCHCRASH
# 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 ) ;
2014-09-02 02:44:43 +00:00
DWORD ( WINAPI * pSymSetOptions ) ( DWORD SymOptions ) ;
BOOL ( WINAPI * pSymInitialize ) ( HANDLE hProcess , PSTR UserSearchPath , BOOL fInvadeProcess ) ;
BOOL ( WINAPI * pSymFromAddr ) ( HANDLE hProcess , DWORD64 Address , PDWORD64 Displacement , PSYMBOL_INFO Symbol ) ;
# ifdef _WIN64
# define DBGHELP_POSTFIX "64"
BOOL ( WINAPI * pStackWalkX ) ( DWORD MachineType , HANDLE hProcess , HANDLE hThread , LPSTACKFRAME64 StackFrame , PVOID ContextRecord , PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine , PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine , PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine , PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ) ;
PVOID ( WINAPI * pSymFunctionTableAccessX ) ( HANDLE hProcess , DWORD64 AddrBase ) ;
DWORD64 ( WINAPI * pSymGetModuleBaseX ) ( HANDLE hProcess , DWORD64 qwAddr ) ;
BOOL ( WINAPI * pSymGetLineFromAddrX ) ( HANDLE hProcess , DWORD64 qwAddr , PDWORD pdwDisplacement , PIMAGEHLP_LINE64 Line64 ) ;
BOOL ( WINAPI * pSymGetModuleInfoX ) ( HANDLE hProcess , DWORD64 qwAddr , PIMAGEHLP_MODULE64 ModuleInfo ) ;
# define STACKFRAMEX STACKFRAME64
# define IMAGEHLP_LINEX IMAGEHLP_LINE64
# define IMAGEHLP_MODULEX IMAGEHLP_MODULE64
# else
# define DBGHELP_POSTFIX ""
BOOL ( WINAPI * pStackWalkX ) ( DWORD MachineType , HANDLE hProcess , HANDLE hThread , LPSTACKFRAME StackFrame , PVOID ContextRecord , PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine , PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine , PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine , PTRANSLATE_ADDRESS_ROUTINE TranslateAddress ) ;
PVOID ( WINAPI * pSymFunctionTableAccessX ) ( HANDLE hProcess , DWORD AddrBase ) ;
DWORD ( WINAPI * pSymGetModuleBaseX ) ( HANDLE hProcess , DWORD dwAddr ) ;
BOOL ( WINAPI * pSymGetLineFromAddrX ) ( HANDLE hProcess , DWORD dwAddr , PDWORD pdwDisplacement , PIMAGEHLP_LINE Line ) ;
BOOL ( WINAPI * pSymGetModuleInfoX ) ( HANDLE hProcess , DWORD dwAddr , PIMAGEHLP_MODULE ModuleInfo ) ;
# define STACKFRAMEX STACKFRAME
# define IMAGEHLP_LINEX IMAGEHLP_LINE
# define IMAGEHLP_MODULEX IMAGEHLP_MODULE
# endif
dllfunction_t debughelpfuncs [ ] =
{
{ ( void * ) & pSymFromAddr , " SymFromAddr " } ,
{ ( void * ) & pSymSetOptions , " SymSetOptions " } ,
{ ( void * ) & pSymInitialize , " SymInitialize " } ,
{ ( void * ) & pStackWalkX , " StackWalk " DBGHELP_POSTFIX } ,
{ ( void * ) & pSymFunctionTableAccessX , " SymFunctionTableAccess " DBGHELP_POSTFIX } ,
{ ( void * ) & pSymGetModuleBaseX , " SymGetModuleBase " DBGHELP_POSTFIX } ,
{ ( void * ) & pSymGetLineFromAddrX , " SymGetLineFromAddr " DBGHELP_POSTFIX } ,
{ ( void * ) & pSymGetModuleInfoX , " SymGetModuleInfo " DBGHELP_POSTFIX } ,
{ NULL , NULL }
} ;
switch ( exceptionCode )
{
case EXCEPTION_ACCESS_VIOLATION :
case EXCEPTION_DATATYPE_MISALIGNMENT :
case EXCEPTION_BREAKPOINT :
case EXCEPTION_SINGLE_STEP :
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
case EXCEPTION_FLT_DENORMAL_OPERAND :
case EXCEPTION_FLT_DIVIDE_BY_ZERO :
case EXCEPTION_FLT_INEXACT_RESULT :
case EXCEPTION_FLT_INVALID_OPERATION :
case EXCEPTION_FLT_OVERFLOW :
case EXCEPTION_FLT_STACK_CHECK :
case EXCEPTION_FLT_UNDERFLOW :
case EXCEPTION_INT_DIVIDE_BY_ZERO :
case EXCEPTION_INT_OVERFLOW :
case EXCEPTION_PRIV_INSTRUCTION :
case EXCEPTION_IN_PAGE_ERROR :
case EXCEPTION_ILLEGAL_INSTRUCTION :
case EXCEPTION_NONCONTINUABLE_EXCEPTION :
case EXCEPTION_STACK_OVERFLOW :
case EXCEPTION_INVALID_DISPOSITION :
case EXCEPTION_GUARD_PAGE :
case EXCEPTION_INVALID_HANDLE :
// case EXCEPTION_POSSIBLE_DEADLOCK:
break ;
default :
//because windows is a steaming pile of shite, we have to ignore any software-generated exceptions, because most of them are not in fact fatal, *EVEN IF THEY CLAIM TO BE NON-CONTINUABLE*
return exceptionCode ;
}
2010-07-18 08:42:59 +00:00
hKernel = LoadLibrary ( " kernel32 " ) ;
pIsDebuggerPresent = ( void * ) GetProcAddress ( hKernel , " IsDebuggerPresent " ) ;
2014-09-02 02:44:43 +00:00
if ( pIsDebuggerPresent & & pIsDebuggerPresent ( ) )
return EXCEPTION_CONTINUE_SEARCH ;
2010-07-18 08:42:59 +00:00
# ifdef GLQUAKE
GLVID_Crashed ( ) ;
# endif
2014-09-02 02:44:43 +00:00
# if 1 //ndef _MSC_VER
2010-07-18 08:42:59 +00:00
{
2014-09-02 02:44:43 +00:00
if ( Sys_LoadLibrary ( " DBGHELP " , debughelpfuncs ) )
{
STACKFRAMEX stack ;
CONTEXT * pcontext = exceptionInfo - > ContextRecord ;
IMAGEHLP_LINEX line ;
IMAGEHLP_MODULEX module ;
struct
{
SYMBOL_INFO sym ;
char name [ 1024 ] ;
} sym ;
int frameno ;
char stacklog [ 8192 ] ;
int logpos , logstart ;
char * logline ;
stacklog [ logpos = 0 ] = 0 ;
pSymInitialize ( hProc , NULL , TRUE ) ;
pSymSetOptions ( SYMOPT_LOAD_LINES ) ;
memset ( & stack , 0 , sizeof ( stack ) ) ;
# ifdef _WIN64
# define IMAGE_FILE_MACHINE_THIS IMAGE_FILE_MACHINE_AMD64
stack . AddrPC . Mode = AddrModeFlat ;
stack . AddrPC . Offset = pcontext - > Rip ;
stack . AddrFrame . Mode = AddrModeFlat ;
stack . AddrFrame . Offset = pcontext - > Rbp ;
stack . AddrStack . Mode = AddrModeFlat ;
stack . AddrStack . Offset = pcontext - > Rsp ;
# else
# define IMAGE_FILE_MACHINE_THIS IMAGE_FILE_MACHINE_I386
stack . AddrPC . Mode = AddrModeFlat ;
stack . AddrPC . Offset = pcontext - > Eip ;
stack . AddrFrame . Mode = AddrModeFlat ;
stack . AddrFrame . Offset = pcontext - > Ebp ;
stack . AddrStack . Mode = AddrModeFlat ;
stack . AddrStack . Offset = pcontext - > Esp ;
# endif
Q_strncpyz ( stacklog + logpos , FULLENGINENAME " or dependancy has crashed. The following stack dump been copied to your windows clipboard. \n "
# ifdef _MSC_VER
" Would you like to generate a core dump too? \n "
# endif
" \n " , sizeof ( stacklog ) - logpos ) ;
logstart = logpos + = strlen ( stacklog + logpos ) ;
//so I know which one it is
# if defined(DEBUG) || defined(_DEBUG)
# define BUILDDEBUGREL "Debug"
# else
# define BUILDDEBUGREL "Optimised"
# endif
# ifdef MINIMAL
# define BUILDMINIMAL "Min"
# else
# define BUILDMINIMAL ""
# endif
# if defined(GLQUAKE) && !defined(D3DQUAKE)
# define BUILDTYPE "GL"
# elif !defined(GLQUAKE) && defined(D3DQUAKE)
# define BUILDTYPE "D3D"
# else
# define BUILDTYPE "Merged"
# endif
Q_snprintfz ( stacklog + logpos , sizeof ( stacklog ) - logpos , " Build: %s %s %s: %s \r \n " , BUILDDEBUGREL , PLATFORM , BUILDMINIMAL BUILDTYPE , version_string ( ) ) ;
logpos + = strlen ( stacklog + logpos ) ;
for ( frameno = 0 ; ; frameno + + )
{
DWORD64 symdisp ;
DWORD linedisp ;
DWORD_PTR symaddr ;
if ( ! pStackWalkX ( IMAGE_FILE_MACHINE_THIS , hProc , GetCurrentThread ( ) , & stack , pcontext , NULL , pSymFunctionTableAccessX , pSymGetModuleBaseX , NULL ) )
break ;
memset ( & module , 0 , sizeof ( module ) ) ;
module . SizeOfStruct = sizeof ( module ) ;
pSymGetModuleInfoX ( hProc , stack . AddrPC . Offset , & module ) ;
memset ( & line , 0 , sizeof ( line ) ) ;
line . SizeOfStruct = sizeof ( line ) ;
symdisp = 0 ;
memset ( & sym , 0 , sizeof ( sym ) ) ;
sym . sym . MaxNameLen = sizeof ( sym . name ) ;
symaddr = stack . AddrPC . Offset ;
sym . sym . SizeOfStruct = sizeof ( sym . sym ) ;
if ( pSymFromAddr ( hProc , symaddr , & symdisp , & sym . sym ) )
{
if ( pSymGetLineFromAddrX ( hProc , stack . AddrPC . Offset , & linedisp , & line ) )
logline = va ( " %-20s - %s:%i (%s) \r \n " , sym . sym . Name , line . FileName , ( int ) line . LineNumber , module . LoadedImageName ) ;
else
logline = va ( " %-20s+%#x (%s) \r \n " , sym . sym . Name , ( unsigned int ) symdisp , module . LoadedImageName ) ;
}
else
logline = va ( " 0x%p (%s) \r \n " , ( void * ) ( DWORD_PTR ) stack . AddrPC . Offset , module . LoadedImageName ) ;
Q_strncpyz ( stacklog + logpos , logline , sizeof ( stacklog ) - logpos ) ;
logpos + = strlen ( stacklog + logpos ) ;
if ( logpos + 1 > = sizeof ( stacklog ) )
break ;
}
Sys_Printf ( " %s " , stacklog + logstart ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
else
{
Sys_Printf ( " We crashed. \n Unable to load dbghelp library. Stack info is not available \n " ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
2010-07-18 08:42:59 +00:00
}
2014-09-02 02:44:43 +00:00
# endif
2010-07-18 08:42:59 +00:00
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
2014-10-05 20:04:11 +00:00
MessageBox ( NULL , " Kaboom! Sorry. No MiniDumpWriteDump function. " , FULLENGINENAME " Sucks " , 0 ) ;
2010-07-18 08:42:59 +00:00
return EXCEPTION_EXECUTE_HANDLER ;
}
2014-09-02 02:44:43 +00:00
LONG CALLBACK nonmsvc_CrashExceptionHandler ( PEXCEPTION_POINTERS ExceptionInfo )
{
DWORD foo = EXCEPTION_CONTINUE_SEARCH ;
foo = CrashExceptionHandler ( /*false, */ ExceptionInfo - > ExceptionRecord - > ExceptionCode , ExceptionInfo ) ;
//we have no handler. thus we handle it by exiting.
if ( foo = = EXCEPTION_EXECUTE_HANDLER )
exit ( 1 ) ;
return foo ;
}
2010-07-18 08:42:59 +00:00
# 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 ;
}
2014-03-30 08:55:06 +00:00
wchar_t * widen ( wchar_t * out , size_t outlen , const char * utf8 ) ;
char * narrowen ( char * out , size_t outlen , wchar_t * wide ) ;
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
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
2015-02-02 08:01:53 +00:00
static time_t Sys_FileTimeToTime ( FILETIME ft )
{
ULARGE_INTEGER ull ;
ull . LowPart = ft . dwLowDateTime ;
ull . HighPart = ft . dwHighDateTime ;
return ull . QuadPart / 10000000ULL - 11644473600ULL ;
}
static int Sys_EnumerateFiles2 ( const char * match , int matchstart , int neststart , int ( QDECL * func ) ( const char * fname , qofs_t fsize , time_t mtime , void * parm , searchpathfuncs_t * spath ) , void * parm , searchpathfuncs_t * spath )
2004-08-23 00:15:46 +00:00
{
2014-03-30 08:55:06 +00:00
qboolean go ;
if ( ! WinNT )
2004-08-23 00:15:46 +00:00
{
2014-03-30 08:55:06 +00:00
HANDLE r ;
WIN32_FIND_DATAA fd ;
int nest = neststart ; //neststart refers to just after a /
qboolean wild = false ;
while ( match [ nest ] & & match [ nest ] ! = ' / ' )
{
if ( match [ nest ] = = ' ? ' | | match [ nest ] = = ' * ' )
wild = true ;
nest + + ;
}
if ( match [ nest ] = = ' / ' )
{
char submatch [ MAX_OSPATH ] ;
char tmproot [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
if ( ! wild )
return Sys_EnumerateFiles2 ( match , matchstart , nest + 1 , func , parm , spath ) ;
if ( nest - neststart + 1 > MAX_OSPATH )
return 1 ;
memcpy ( submatch , match + neststart , nest - neststart ) ;
submatch [ nest - neststart ] = 0 ;
nest + + ;
if ( neststart + 4 > MAX_OSPATH )
return 1 ;
memcpy ( tmproot , match , neststart ) ;
strcpy ( tmproot + neststart , " *.* " ) ;
r = FindFirstFile ( tmproot , & fd ) ;
strcpy ( tmproot + neststart , " " ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
if ( * fd . cFileName = = ' . ' ) ; //don't ever find files with a name starting with '.'
else if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
{
if ( wildcmp ( submatch , fd . cFileName ) )
{
int newnest ;
if ( strlen ( tmproot ) + strlen ( fd . cFileName ) + strlen ( match + nest ) + 2 < MAX_OSPATH )
{
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , tmproot , fd . cFileName ) ;
newnest = strlen ( file ) ;
strcpy ( file + newnest , match + nest ) ;
go = Sys_EnumerateFiles2 ( file , matchstart , newnest , func , parm , spath ) ;
}
}
}
} while ( FindNextFile ( r , & fd ) & & go ) ;
FindClose ( r ) ;
}
else
{
const char * submatch = match + neststart ;
char tmproot [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
if ( neststart + 4 > MAX_OSPATH )
return 1 ;
memcpy ( tmproot , match , neststart ) ;
strcpy ( tmproot + neststart , " *.* " ) ;
r = FindFirstFile ( tmproot , & fd ) ;
strcpy ( tmproot + neststart , " " ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
if ( * fd . cFileName = = ' . ' )
; //don't ever find files with a name starting with '.' (includes .. and . directories, and unix hidden files)
else if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
{
if ( wildcmp ( submatch , fd . cFileName ) )
{
if ( strlen ( tmproot + matchstart ) + strlen ( fd . cFileName ) + 2 < MAX_OSPATH )
{
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , tmproot + matchstart , fd . cFileName ) ;
2015-02-02 08:01:53 +00:00
go = func ( file , qofs_Make ( fd . nFileSizeLow , fd . nFileSizeHigh ) , Sys_FileTimeToTime ( fd . ftLastWriteTime ) , parm , spath ) ;
2014-03-30 08:55:06 +00:00
}
}
}
else
{
if ( wildcmp ( submatch , fd . cFileName ) )
{
if ( strlen ( tmproot + matchstart ) + strlen ( fd . cFileName ) + 1 < MAX_OSPATH )
{
Q_snprintfz ( file , sizeof ( file ) , " %s%s " , tmproot + matchstart , fd . cFileName ) ;
2015-02-02 08:01:53 +00:00
go = func ( file , qofs_Make ( fd . nFileSizeLow , fd . nFileSizeHigh ) , Sys_FileTimeToTime ( fd . ftLastWriteTime ) , parm , spath ) ;
2014-03-30 08:55:06 +00:00
}
}
}
} while ( FindNextFile ( r , & fd ) & & go ) ;
FindClose ( r ) ;
}
2004-08-23 00:15:46 +00:00
}
2014-03-30 08:55:06 +00:00
else
{
HANDLE r ;
WIN32_FIND_DATAW fd ;
int nest = neststart ; //neststart refers to just after a /
qboolean wild = false ;
2010-12-15 12:29:58 +00:00
2014-03-30 08:55:06 +00:00
while ( match [ nest ] & & match [ nest ] ! = ' / ' )
{
if ( match [ nest ] = = ' ? ' | | match [ nest ] = = ' * ' )
wild = true ;
nest + + ;
}
if ( match [ nest ] = = ' / ' )
{
char submatch [ MAX_OSPATH ] ;
char tmproot [ MAX_OSPATH ] ;
2004-08-23 00:15:46 +00:00
2014-03-30 08:55:06 +00:00
if ( ! wild )
return Sys_EnumerateFiles2 ( match , matchstart , nest + 1 , func , parm , spath ) ;
if ( nest - neststart + 1 > MAX_OSPATH )
return 1 ;
memcpy ( submatch , match + neststart , nest - neststart ) ;
submatch [ nest - neststart ] = 0 ;
nest + + ;
if ( neststart + 4 > MAX_OSPATH )
return 1 ;
memcpy ( tmproot , match , neststart ) ;
strcpy ( tmproot + neststart , " *.* " ) ;
2004-08-23 00:15:46 +00:00
{
2014-03-30 08:55:06 +00:00
wchar_t wroot [ MAX_OSPATH ] ;
r = FindFirstFileW ( widen ( wroot , sizeof ( wroot ) , tmproot ) , & fd ) ;
2004-08-23 00:15:46 +00:00
}
2014-03-30 08:55:06 +00:00
strcpy ( tmproot + neststart , " " ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
char utf8 [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
narrowen ( utf8 , sizeof ( utf8 ) , fd . cFileName ) ;
if ( * utf8 = = ' . ' ) ; //don't ever find files with a name starting with '.'
else if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
{
if ( wildcmp ( submatch , utf8 ) )
{
int newnest ;
if ( strlen ( tmproot ) + strlen ( utf8 ) + strlen ( match + nest ) + 2 < MAX_OSPATH )
{
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , tmproot , utf8 ) ;
newnest = strlen ( file ) ;
strcpy ( file + newnest , match + nest ) ;
go = Sys_EnumerateFiles2 ( file , matchstart , newnest , func , parm , spath ) ;
}
}
}
} while ( FindNextFileW ( r , & fd ) & & go ) ;
FindClose ( r ) ;
2004-08-23 00:15:46 +00:00
}
2005-05-30 12:30:41 +00:00
else
{
2014-03-30 08:55:06 +00:00
const char * submatch = match + neststart ;
char tmproot [ MAX_OSPATH ] ;
if ( neststart + 4 > MAX_OSPATH )
return 1 ;
memcpy ( tmproot , match , neststart ) ;
strcpy ( tmproot + neststart , " *.* " ) ;
{
wchar_t wroot [ MAX_OSPATH ] ;
r = FindFirstFileW ( widen ( wroot , sizeof ( wroot ) , tmproot ) , & fd ) ;
}
strcpy ( tmproot + neststart , " " ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
char utf8 [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
narrowen ( utf8 , sizeof ( utf8 ) , fd . cFileName ) ;
if ( * utf8 = = ' . ' )
; //don't ever find files with a name starting with '.' (includes .. and . directories, and unix hidden files)
else if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
{
if ( wildcmp ( submatch , utf8 ) )
{
if ( strlen ( tmproot + matchstart ) + strlen ( utf8 ) + 2 < MAX_OSPATH )
{
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , tmproot + matchstart , utf8 ) ;
2015-02-02 08:01:53 +00:00
go = func ( file , qofs_Make ( fd . nFileSizeLow , fd . nFileSizeHigh ) , Sys_FileTimeToTime ( fd . ftLastWriteTime ) , parm , spath ) ;
2014-03-30 08:55:06 +00:00
}
}
}
else
{
if ( wildcmp ( submatch , utf8 ) )
{
if ( strlen ( tmproot + matchstart ) + strlen ( utf8 ) + 1 < MAX_OSPATH )
{
Q_snprintfz ( file , sizeof ( file ) , " %s%s " , tmproot + matchstart , utf8 ) ;
2015-02-02 08:01:53 +00:00
go = func ( file , qofs_Make ( fd . nFileSizeLow , fd . nFileSizeHigh ) , Sys_FileTimeToTime ( fd . ftLastWriteTime ) , parm , spath ) ;
2014-03-30 08:55:06 +00:00
}
}
}
} while ( FindNextFileW ( r , & fd ) & & go ) ;
FindClose ( r ) ;
2005-05-30 12:30:41 +00:00
}
2004-08-23 00:15:46 +00:00
}
return go ;
}
2015-02-02 08:01:53 +00:00
int Sys_EnumerateFiles ( const char * gpath , const char * match , int ( QDECL * func ) ( const char * fname , qofs_t fsize , time_t mtime , void * parm , searchpathfuncs_t * spath ) , void * parm , searchpathfuncs_t * spath )
2014-03-30 08:55:06 +00:00
{
char fullmatch [ MAX_OSPATH ] ;
int start ;
if ( strlen ( gpath ) + strlen ( match ) + 2 > MAX_OSPATH )
return 1 ;
strcpy ( fullmatch , gpath ) ;
start = strlen ( fullmatch ) ;
if ( start & & fullmatch [ start - 1 ] ! = ' / ' )
fullmatch [ start + + ] = ' / ' ;
fullmatch [ start ] = 0 ;
strcat ( fullmatch , match ) ;
return Sys_EnumerateFiles2 ( fullmatch , start , start , func , parm , spath ) ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
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 " ) )
2014-09-02 02:44:43 +00:00
{
2006-01-02 22:36:12 +00:00
Sys_Quit ( ) ;
2014-09-02 02:44:43 +00:00
exit ( 1 ) ;
}
2006-01-02 22:36:12 +00:00
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 ( ) )
2014-09-02 02:44:43 +00:00
{
2004-08-23 00:15:46 +00:00
Sys_Quit ( ) ;
2014-09-02 02:44:43 +00:00
exit ( 1 ) ;
}
2004-08-23 00:15:46 +00:00
}
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
= = = = = = = = = = = = = = = =
*/
2014-03-30 08:55:06 +00:00
void SV_GetNewSpawnParms ( client_t * cl ) ;
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 ;
}
2014-03-30 08:55:06 +00:00
# ifdef SUBSERVERS
if ( SSV_IsSubServer ( ) )
{
DWORD avail ;
static char text [ 1024 ] , * nl ;
static int textpos = 0 ;
HANDLE input = GetStdHandle ( STD_INPUT_HANDLE ) ;
if ( ! PeekNamedPipe ( input , NULL , 0 , NULL , & avail , NULL ) )
{
SV_FinalMessage ( " Cluster shut down \n " ) ;
Cmd_ExecuteString ( " quit force " , RESTRICT_LOCAL ) ;
}
else if ( avail )
{
if ( avail > sizeof ( text ) - 1 - textpos )
avail = sizeof ( text ) - 1 - textpos ;
if ( ReadFile ( input , text + textpos , avail , & avail , NULL ) )
{
textpos + = avail ;
while ( textpos > = 2 )
{
unsigned short len = text [ 0 ] | ( text [ 1 ] < < 8 ) ;
if ( textpos > = len & & len > = 2 )
{
memcpy ( net_message . data , text + 2 , len - 2 ) ;
net_message . cursize = len - 2 ;
MSG_BeginReading ( msg_nullnetprim ) ;
SSV_ReadFromControlServer ( ) ;
memmove ( text , text + len , textpos - len ) ;
textpos - = len ;
}
else
break ;
}
}
}
return NULL ;
}
# endif
2004-08-23 00:15:46 +00:00
// 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 ) ;
2014-03-30 08:55:06 +00:00
# ifdef SUBSERVERS
if ( SSV_IsSubServer ( ) )
{
SSV_PrintToMaster ( msg ) ;
return ;
}
# endif
2005-10-04 21:16:47 +00:00
{
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 ;
2014-07-02 03:20:40 +00:00
float delay = 0.001 ;
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 ;
2014-07-02 03:20:40 +00:00
delay = SV_Frame ( ) ;
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
int main ( int argc , char * * argv )
{
2010-07-18 08:42:59 +00:00
# ifdef CATCHCRASH
2014-09-14 01:45:11 +00:00
LoadLibrary ( " DBGHELP " ) ; //heap corruption can prevent loadlibrary from working properly, so do this in advance.
2014-09-02 02:44:43 +00:00
# ifdef _MSC_VER
2010-07-18 08:42:59 +00:00
__try
2014-09-02 02:44:43 +00:00
# else
AddVectoredExceptionHandler ( true , nonmsvc_CrashExceptionHandler ) ;
# endif
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 ) ;
2014-09-02 02:44:43 +00:00
# ifdef SUBSERVERS
isClusterSlave = COM_CheckParm ( " -clusterslave " ) ;
# endif
# ifdef USESERVICE
if ( ! SSV_IsSubServer ( ) & & StartServiceCtrlDispatcher ( DispatchTable ) )
{
return true ;
}
# endif
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
2014-03-30 08:55:06 +00:00
2010-07-18 08:42:59 +00:00
StartQuakeServer ( ) ;
ServerMainLoop ( ) ;
}
# ifdef CATCHCRASH
2014-09-02 02:44:43 +00:00
# ifdef _MSC_VER
2010-07-18 08:42:59 +00:00
__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
}
2014-09-02 02:44:43 +00:00
# endif
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 ;
}
2015-01-21 18:18:37 +00:00
# ifdef HAVEAUTOUPDATE
2015-01-21 21:33:04 +00:00
int Sys_GetAutoUpdateSetting ( void )
2015-01-21 18:18:37 +00:00
{
return - 1 ;
}
void Sys_SetAutoUpdateSetting ( int newval )
{
}
# endif
2007-12-30 00:09:34 +00:00
# endif