Updated platform files to ioq3 codebase

This commit is contained in:
L 2023-01-31 00:53:24 +01:00
parent 0d074c09e8
commit dc36511b5a
16 changed files with 2248 additions and 884 deletions

View file

@ -106,6 +106,10 @@ set(SOURCES_COMMON
"code/qcommon/tiki_main.cpp" "code/qcommon/tiki_main.cpp"
"code/qcommon/tiki_script.cpp" "code/qcommon/tiki_script.cpp"
"code/qcommon/unzip.c" "code/qcommon/unzip.c"
# Main stuff
"code/sys/sys_main.c"
"code/sys/sys_autoupdater.c"
"code/sys/con_log.c"
) )
file(GLOB_RECURSE SOURCES_SKEL "code/tiki/*.cpp" "code/skeletor/*.cpp") file(GLOB_RECURSE SOURCES_SKEL "code/tiki/*.cpp" "code/skeletor/*.cpp")
@ -124,7 +128,7 @@ set(SOURCES_APP ${SOURCES_SHARED} ${SOURCES_COMMON} ${SOURCES_SKEL})
file(GLOB_RECURSE SOURCES_SERVER "code/server/*.c" "code/server/*.cpp") file(GLOB_RECURSE SOURCES_SERVER "code/server/*.c" "code/server/*.cpp")
set(SOURCES_SERVER_APP ${SOURCES_APP} ${SOURCES_SERVER}) set(SOURCES_SERVER_APP ${SOURCES_APP} ${SOURCES_SERVER})
add_executable(omohaaded ${SOURCES_SERVER_APP} ${SOURCES_PLATFORM_SPECIFIC} "code/null/null_client.c" "code/null/null_input.c" "code/null/null_snddma.c" "code/sys/sys_main.c" "code/sys/con_log.c") add_executable(omohaaded ${SOURCES_SERVER_APP} ${SOURCES_PLATFORM_SPECIFIC} "code/null/null_client.c" "code/null/null_input.c" "code/null/null_snddma.c")
set_property(TARGET omohaaded PROPERTY CXX_STANDARD 11) set_property(TARGET omohaaded PROPERTY CXX_STANDARD 11)
target_compile_features(omohaaded PUBLIC cxx_constexpr) target_compile_features(omohaaded PUBLIC cxx_constexpr)
target_compile_definitions(omohaaded PRIVATE NO_SCRIPTENGINE DEDICATED TARGET_GAME_TYPE=${TARGET_GAME_TYPE}) target_compile_definitions(omohaaded PRIVATE NO_SCRIPTENGINE DEDICATED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})

View file

@ -83,7 +83,8 @@ int Sys_Milliseconds (void) {
return 0; return 0;
} }
void Sys_Mkdir (char *path) { qboolean Sys_Mkdir (const char *path) {
return qfalse;
} }
char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave) { char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave) {

View file

@ -99,6 +99,7 @@ cvar_t *com_cameraMode;
cvar_t *com_ansiColor; cvar_t *com_ansiColor;
cvar_t *com_unfocused; cvar_t *com_unfocused;
cvar_t *com_minimized; cvar_t *com_minimized;
cvar_t *com_homepath;
cvar_t *precache; cvar_t *precache;
// com_speeds times // com_speeds times
@ -291,7 +292,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) {
lastErrorTime = currentTime; lastErrorTime = currentTime;
if ( com_errorEntered ) { if ( com_errorEntered ) {
SyScriptError( "recursive error after: %s", com_errorMessage ); Sys_Error( "recursive error after: %s", com_errorMessage );
} }
com_errorEntered = qtrue; com_errorEntered = qtrue;
@ -336,7 +337,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) {
Com_Shutdown (); Com_Shutdown ();
SyScriptError ("%s", com_errorMessage); Sys_Error("%s", com_errorMessage);
} }
@ -1266,7 +1267,7 @@ void Com_Init( char *commandLine ) {
Com_Printf( "%s %s %s\n", PRODUCT_VERSION_FULL, PLATFORM_STRING, __DATE__ ); Com_Printf( "%s %s %s\n", PRODUCT_VERSION_FULL, PLATFORM_STRING, __DATE__ );
if ( setjmp (abortframe) ) { if ( setjmp (abortframe) ) {
SyScriptError ("Error during initialization"); Sys_Error("Error during initialization");
} }
// prepare enough of the subsystems to handle // prepare enough of the subsystems to handle
@ -1291,6 +1292,8 @@ void Com_Init( char *commandLine ) {
// done early so bind command exists // done early so bind command exists
CL_InitKeyCommands(); CL_InitKeyCommands();
com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT|CVAR_ROM);
FS_InitFilesystem (); FS_InitFilesystem ();
Com_InitJournaling(); Com_InitJournaling();
@ -1404,7 +1407,7 @@ void Com_Init( char *commandLine ) {
} }
} }
s = va( "%s %s %s", PRODUCT_VERSION_FULL, PLATFORM_STRING, __DATE__ ); s = va( "%s %s %s", PRODUCT_VERSION_FULL, PLATFORM_STRING, PRODUCT_DATE );
com_version = Cvar_Get( "version", s, CVAR_ROM | CVAR_SERVERINFO ); com_version = Cvar_Get( "version", s, CVAR_ROM | CVAR_SERVERINFO );
com_shortversion = Cvar_Get( "shortversion", TARGET_GAME_VERSION, CVAR_ROM ); com_shortversion = Cvar_Get( "shortversion", TARGET_GAME_VERSION, CVAR_ROM );

View file

@ -245,8 +245,7 @@ cvar_t *fs_basepath;
static cvar_t *fs_basegame; static cvar_t *fs_basegame;
static cvar_t *fs_gamedirvar; static cvar_t *fs_gamedirvar;
static cvar_t *fs_restrict; static cvar_t *fs_restrict;
static cvar_t *fs_userpath; static cvar_t *fs_homepath;
static cvar_t *fs_outputpath;
static cvar_t *fs_copyfiles; static cvar_t *fs_copyfiles;
static cvar_t *fs_filedir; static cvar_t *fs_filedir;
static searchpath_t *fs_searchpaths; static searchpath_t *fs_searchpaths;
@ -671,7 +670,7 @@ qboolean FS_FileExists( const char *file )
FILE *f; FILE *f;
char *testpath; char *testpath;
testpath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, file ); testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );
f = fopen( testpath, "rb" ); f = fopen( testpath, "rb" );
if (f) { if (f) {
@ -693,7 +692,7 @@ qboolean FS_SV_FileExists( const char *file )
FILE *f; FILE *f;
char *testpath; char *testpath;
testpath = FS_BuildOSPath( fs_outputpath->string, file, ""); testpath = FS_BuildOSPath( fs_homepath->string, file, "");
testpath[strlen(testpath)-1] = '\0'; testpath[strlen(testpath)-1] = '\0';
f = fopen( testpath, "rb" ); f = fopen( testpath, "rb" );
@ -718,7 +717,7 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
} }
ospath = FS_BuildOSPath( fs_outputpath->string, filename, "" ); ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
ospath[strlen(ospath)-1] = '\0'; ospath[strlen(ospath)-1] = '\0';
f = FS_HandleForFile(); f = FS_HandleForFile();
@ -769,20 +768,20 @@ int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {
S_ClearSoundBuffer(); S_ClearSoundBuffer();
// search homepath // search homepath
ospath = FS_BuildOSPath( fs_outputpath->string, filename, "" ); ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
// remove trailing slash // remove trailing slash
ospath[strlen(ospath)-1] = '\0'; ospath[strlen(ospath)-1] = '\0';
if ( fs_debug->integer ) { if ( fs_debug->integer ) {
Com_Printf( "FS_SV_FOpenFileRead (fs_outputpath): %s\n", ospath ); Com_Printf( "FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath );
} }
fsh[f].handleFiles.file.o = fopen( ospath, "rb" ); fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
fsh[f].handleSync = qfalse; fsh[f].handleSync = qfalse;
if (!fsh[f].handleFiles.file.o) if (!fsh[f].handleFiles.file.o)
{ {
// If fs_outputpath == fs_basepath, don't bother // If fs_homepath == fs_basepath, don't bother
if (Q_stricmp(fs_outputpath->string,fs_basepath->string)) if (Q_stricmp(fs_homepath->string,fs_basepath->string))
{ {
// search basepath // search basepath
ospath = FS_BuildOSPath( fs_basepath->string, filename, "" ); ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
@ -827,8 +826,8 @@ void FS_SV_Rename( const char *from, const char *to ) {
// don't let sound stutter // don't let sound stutter
S_ClearSoundBuffer(); S_ClearSoundBuffer();
from_ospath = FS_BuildOSPath( fs_outputpath->string, from, "" ); from_ospath = FS_BuildOSPath( fs_homepath->string, from, "" );
to_ospath = FS_BuildOSPath( fs_outputpath->string, to, "" ); to_ospath = FS_BuildOSPath( fs_homepath->string, to, "" );
from_ospath[strlen(from_ospath)-1] = '\0'; from_ospath[strlen(from_ospath)-1] = '\0';
to_ospath[strlen(to_ospath)-1] = '\0'; to_ospath[strlen(to_ospath)-1] = '\0';
@ -861,8 +860,8 @@ void FS_Rename( const char *from, const char *to ) {
// don't let sound stutter // don't let sound stutter
S_ClearSoundBuffer(); S_ClearSoundBuffer();
from_ospath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, from ); from_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, from );
to_ospath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, to ); to_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, to );
if ( fs_debug->integer ) { if ( fs_debug->integer ) {
Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath ); Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath );
@ -923,7 +922,7 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) {
f = FS_HandleForFile(); f = FS_HandleForFile();
fsh[f].zipFile = qfalse; fsh[f].zipFile = qfalse;
ospath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, filename ); ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
if ( fs_debug->integer ) { if ( fs_debug->integer ) {
Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); Com_Printf( "FS_FOpenFileWrite: %s\n", ospath );
@ -962,7 +961,7 @@ fileHandle_t FS_FOpenTextFileWrite( const char *filename ) {
Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
ospath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, filename ); ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
if ( fs_debug->integer ) { if ( fs_debug->integer ) {
Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); Com_Printf( "FS_FOpenFileWrite: %s\n", ospath );
@ -1002,7 +1001,7 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) {
// don't let sound stutter // don't let sound stutter
S_ClearSoundBuffer(); S_ClearSoundBuffer();
ospath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, filename ); ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
if ( fs_debug->integer ) { if ( fs_debug->integer ) {
Com_Printf( "FS_FOpenFileAppend: %s\n", ospath ); Com_Printf( "FS_FOpenFileAppend: %s\n", ospath );
@ -1084,7 +1083,7 @@ void FS_DeleteFile( const char *filename )
Com_Error( 0, "Filesystem call made without initialization\n" ); Com_Error( 0, "Filesystem call made without initialization\n" );
} }
ospath = FS_BuildOSPath( fs_outputpath->string, fs_gamedir, filename ); ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
if( fs_debug->integer ) { if( fs_debug->integer ) {
Com_Printf( "FS_DeleteFile: %s\n", ospath ); Com_Printf( "FS_DeleteFile: %s\n", ospath );
@ -1130,7 +1129,6 @@ Used for streaming data out of either a
separate file or a ZIP file. separate file or a ZIP file.
=========== ===========
*/ */
extern "C" qboolean com_fullyInitialized;
int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE, qboolean quiet ) { int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE, qboolean quiet ) {
searchpath_t *search; searchpath_t *search;
@ -1288,7 +1286,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF
continue; continue;
} }
} }
dir = search->dir; dir = search->dir;
netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
@ -2397,7 +2395,7 @@ int FS_GetModList( char *listbuf, int bufsize ) {
nMods = 0; nMods = 0;
nPotential = nTotal = 0; nPotential = nTotal = 0;
pFiles0 = Sys_ListFiles( fs_outputpath->string, NULL, NULL, &dummy, qtrue ); pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue ); pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
// we searched for mods in the three paths // we searched for mods in the three paths
// it is likely that we have duplicate names now, which we will cleanup below // it is likely that we have duplicate names now, which we will cleanup below
@ -2437,7 +2435,7 @@ int FS_GetModList( char *listbuf, int bufsize ) {
/* try on home path */ /* try on home path */
if ( nPaks <= 0 ) if ( nPaks <= 0 )
{ {
path = FS_BuildOSPath( fs_outputpath->string, name, "" ); path = FS_BuildOSPath( fs_homepath->string, name, "" );
nPaks = 0; nPaks = 0;
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse ); pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
Sys_FreeFileList( pPaks ); Sys_FreeFileList( pPaks );
@ -3072,13 +3070,20 @@ FS_Startup
*/ */
static void FS_Startup( const char *gameName ) static void FS_Startup( const char *gameName )
{ {
const char* homePath;
if( !silentStart ) { if( !silentStart ) {
Com_Printf( "----- FS_Startup -----\n" ); Com_Printf( "----- FS_Startup -----\n" );
} }
fs_debug = Cvar_Get( "fs_debug", "0", 0 ); fs_debug = Cvar_Get( "fs_debug", "0", 0 );
fs_copyfiles = Cvar_Get( "fs_copyfiles", "0", CVAR_INIT ); fs_copyfiles = Cvar_Get( "fs_copyfiles", "0", CVAR_INIT );
fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultBasePath(), CVAR_INIT ); fs_basepath = Cvar_Get("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT);
homePath = Sys_DefaultHomePath();
if (!homePath || !homePath[0]) {
homePath = fs_basepath->string;
}
fs_homepath = Cvar_Get("fs_homepath", homePath, CVAR_INIT | CVAR_ROM);
fs_gamedirvar = Cvar_Get( "fs_game", "", CVAR_INIT | CVAR_SYSTEMINFO ); fs_gamedirvar = Cvar_Get( "fs_game", "", CVAR_INIT | CVAR_SYSTEMINFO );
fs_restrict = Cvar_Get( "fs_restrict", "", CVAR_INIT ); fs_restrict = Cvar_Get( "fs_restrict", "", CVAR_INIT );
@ -3097,14 +3102,7 @@ static void FS_Startup( const char *gameName )
Cmd_AddCommand ("fdir", FS_NewDir_f ); Cmd_AddCommand ("fdir", FS_NewDir_f );
Cmd_AddCommand ("touchFile", FS_TouchFile_f ); Cmd_AddCommand ("touchFile", FS_TouchFile_f );
fs_userpath = Cvar_Get( "fs_userpath", Sys_DefaultUserPath(), CVAR_INIT ); Sys_Mkdir(fs_homepath->string);
fs_outputpath = Cvar_Get( "fs_outputpath", Sys_DefaultOutputPath(), CVAR_INIT );
Sys_Mkdir( fs_userpath->string );
Sys_Mkdir( fs_outputpath->string );
FS_AddGameDirectory( fs_userpath->string, gameName );
if( !silentStart ) { if( !silentStart ) {
// print the current search paths // print the current search paths
@ -3593,8 +3591,7 @@ void FS_InitFilesystem( void ) {
Com_StartupVariable( "fs_game" ); Com_StartupVariable( "fs_game" );
Com_StartupVariable( "fs_copyfiles" ); Com_StartupVariable( "fs_copyfiles" );
Com_StartupVariable( "fs_restrict" ); Com_StartupVariable( "fs_restrict" );
Com_StartupVariable( "fs_userpath" ); Com_StartupVariable( "fs_homepath" );
Com_StartupVariable( "fs_outputpath" );
// try to start up normally // try to start up normally
FS_Startup( BASEGAME ); FS_Startup( BASEGAME );
@ -3893,3 +3890,8 @@ void FS_GetRelativeFilename( const char *currentDirectory, const char *absoluteF
// copy the rest of the filename into the result string // copy the rest of the filename into the result string
strcpy( &out[ rfMarker ], &absoluteFilename[ afMarker ] ); strcpy( &out[ rfMarker ], &absoluteFilename[ afMarker ] );
} }
const char* FS_GetCurrentGameDir()
{
return fs_gamedirvar->string;
}

View file

@ -220,6 +220,30 @@ void COM_StripExtension( const char *in, char *out, int destsize ) {
out[length] = 0; out[length] = 0;
} }
/*
============
COM_CompareExtension
string compare the end of the strings and return qtrue if strings match
============
*/
qboolean COM_CompareExtension(const char* in, const char* ext)
{
int inlen, extlen;
inlen = strlen(in);
extlen = strlen(ext);
if (extlen <= inlen)
{
in += inlen - extlen;
if (!Q_stricmp(in, ext))
return qtrue;
}
return qfalse;
}
/* /*
================== ==================
@ -1040,34 +1064,86 @@ int Com_HexStrToInt( const char *str )
============================================================================ ============================================================================
*/ */
int Q_isprint( int c ) int Q_isprint(int c)
{ {
if ( c >= 0x20 && c <= 0x7E ) if (c >= 0x20 && c <= 0x7E)
return ( 1 ); return (1);
return ( 0 ); return (0);
} }
int Q_islower( int c ) int Q_islower(int c)
{ {
if (c >= 'a' && c <= 'z') if (c >= 'a' && c <= 'z')
return ( 1 ); return (1);
return ( 0 ); return (0);
} }
int Q_isupper( int c ) int Q_isupper(int c)
{ {
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')
return ( 1 ); return (1);
return ( 0 ); return (0);
} }
int Q_isalpha( int c ) int Q_isalpha(int c)
{ {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
return ( 1 ); return (1);
return ( 0 ); return (0);
} }
qboolean Q_isanumber(const char* s)
{
char* p;
double d;
if (*s == '\0')
return qfalse;
d = strtod(s, &p);
return *p == '\0';
}
qboolean Q_isintegral(float f)
{
return (int)f == f;
}
#ifdef _WIN32
/*
=============
Q_vsnprintf
Special wrapper function for Microsoft's broken _vsnprintf() function.
MinGW comes with its own vsnprintf() which is not broken. mingw-w64
however, uses Microsoft's broken _vsnprintf() function.
=============
*/
int Q_vsnprintf(char* str, size_t size, const char* format, va_list ap)
{
int retval;
retval = _vsnprintf(str, size, format, ap);
if (retval < 0 || retval == size)
{
// Microsoft doesn't adhere to the C99 standard of vsnprintf,
// which states that the return value must be the number of
// bytes written if the output string had sufficient length.
//
// Obviously we cannot determine that value from Microsoft's
// implementation, so we have no choice but to return size.
str[size - 1] = '\0';
return size;
}
return retval;
}
#endif
char* Q_strrchr( const char* string, int c ) char* Q_strrchr( const char* string, int c )
{ {
char cc = c; char cc = c;
@ -1325,24 +1401,18 @@ char *Q_CleanStr( char *string ) {
} }
void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { int QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
size_t len; int len;
va_list argptr; va_list argptr;
char bigbuffer[32000]; // big, but small enough to fit in PPC stack
va_start (argptr,fmt); va_start(argptr, fmt);
len = vsprintf (bigbuffer,fmt,argptr); len = Q_vsnprintf(dest, size, fmt, argptr);
va_end (argptr); va_end(argptr);
if ( len >= sizeof( bigbuffer ) ) {
Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); if (len >= size)
} Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len + 1);
if (len >= size) {
Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); return len;
#ifdef _DEBUG
__debugbreak();
#endif
}
Q_strncpyz (dest, bigbuffer, size );
} }
void Com_BackslashToSlash( char *str ) void Com_BackslashToSlash( char *str )

View file

@ -31,6 +31,7 @@ extern "C" {
#define PRODUCT_NAME "OpenMoHAA" #define PRODUCT_NAME "OpenMoHAA"
#define PRODUCT_VERSION "0.49-alpha" #define PRODUCT_VERSION "0.49-alpha"
#define PRODUCT_DATE __DATE__
#if TARGET_GAME_TYPE == 1 #if TARGET_GAME_TYPE == 1
// Team Assault // Team Assault
@ -39,6 +40,10 @@ extern "C" {
// The version string must be equal or above 2.0 to be able to connect to spearhead servers // The version string must be equal or above 2.0 to be able to connect to spearhead servers
#define TARGET_GAME_VERSION "2.41" #define TARGET_GAME_VERSION "2.41"
#define TARGET_GAME_PROTOCOL 17 #define TARGET_GAME_PROTOCOL 17
#define HOMEPATH_NAME_UNIX ".mohta"
#define HOMEPATH_NAME_WIN "mohta"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
#elif TARGET_GAME_TYPE == 2 #elif TARGET_GAME_TYPE == 2
// Team Tactics // Team Tactics
#define BASEGAME "maintt" #define BASEGAME "maintt"
@ -46,6 +51,10 @@ extern "C" {
// The version string must be equal or above 2.0 to be able to connect to breakthrough servers // The version string must be equal or above 2.0 to be able to connect to breakthrough servers
#define TARGET_GAME_VERSION "2.41" #define TARGET_GAME_VERSION "2.41"
#define TARGET_GAME_PROTOCOL 17 #define TARGET_GAME_PROTOCOL 17
#define HOMEPATH_NAME_UNIX ".mohtt"
#define HOMEPATH_NAME_WIN "mohtt"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
#else #else
// The default: the base game (no expansion) // The default: the base game (no expansion)
@ -54,6 +63,10 @@ extern "C" {
// The version string must be below 1.12, otherwise it's not possible to connect // The version string must be below 1.12, otherwise it's not possible to connect
#define TARGET_GAME_VERSION "1.12" #define TARGET_GAME_VERSION "1.12"
#define TARGET_GAME_PROTOCOL 8 #define TARGET_GAME_PROTOCOL 8
#define HOMEPATH_NAME_UNIX ".moh"
#define HOMEPATH_NAME_WIN "moh"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
#endif #endif
#define PRODUCT_NAME_FULL PRODUCT_NAME ": " PRODUCT_EXTENSION #define PRODUCT_NAME_FULL PRODUCT_NAME ": " PRODUCT_EXTENSION
@ -141,28 +154,25 @@ extern "C" {
#ifdef _MSC_VER #ifdef _MSC_VER
#include <io.h> #include <io.h>
#ifndef _STDINT typedef __int64 int64_t;
typedef __int64 int64_t; typedef __int32 int32_t;
typedef __int32 int32_t; typedef __int16 int16_t;
typedef __int16 int16_t; typedef __int8 int8_t;
typedef __int8 int8_t; typedef unsigned __int64 uint64_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int16 uint16_t;
typedef unsigned __int16 uint16_t; typedef unsigned __int8 uint8_t;
typedef unsigned __int8 uint8_t;
#endif
// vsnprintf is ISO/IEC 9899:1999
// abstracting this to make it portable
int Q_vsnprintf( char *str, size_t size, const char *format, va_list ap );
#else #else
#include <stdint.h> #include <stdint.h>
#define Q_vsnprintf vsnprintf
#endif #endif
#define HAVE_STDINT_H #ifdef _WIN32
#define _HAVE_STDINT_H 1 // vsnprintf is ISO/IEC 9899:1999
// abstracting this to make it portable
int Q_vsnprintf(char* str, size_t size, const char* format, va_list ap);
#else
#define Q_vsnprintf vsnprintf
#endif
#endif #endif
@ -1097,6 +1107,7 @@ float Com_Clamp( float min, float max, float value );
const char *COM_SkipPath( const char *pathname ); const char *COM_SkipPath( const char *pathname );
const char *COM_GetExtension( const char *name ); const char *COM_GetExtension( const char *name );
void COM_StripExtension(const char *in, char *out, int destsize); void COM_StripExtension(const char *in, char *out, int destsize);
qboolean COM_CompareExtension(const char* in, const char* ext);
void COM_DefaultExtension( char *path, int maxSize, const char *extension ); void COM_DefaultExtension( char *path, int maxSize, const char *extension );
void COM_BeginParseSession( const char *name ); void COM_BeginParseSession( const char *name );
@ -1147,7 +1158,7 @@ void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);
int Com_HexStrToInt( const char *str ); int Com_HexStrToInt( const char *str );
void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); int QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
char *Com_SkipTokens( char *s, int numTokens, char *sep ); char *Com_SkipTokens( char *s, int numTokens, char *sep );
char *Com_SkipCharset( char *s, char *sep ); char *Com_SkipCharset( char *s, char *sep );

View file

@ -647,7 +647,7 @@ qboolean FS_FileExists( const char *file );
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
qboolean FS_CreatePath( char *OSPath ); qboolean FS_CreatePath(char *OSPath);
int FS_LoadStack( void ); int FS_LoadStack( void );
@ -767,6 +767,7 @@ void FS_Remove( const char *osPath );
void FS_FilenameCompletion( const char *dir, const char *ext, void FS_FilenameCompletion( const char *dir, const char *ext,
qboolean stripExt, void(*callback)(const char *s) ); qboolean stripExt, void(*callback)(const char *s) );
const char* FS_GetCurrentGameDir();
void FS_GetRelativeFilename( const char *currentDirectory, const char *absoluteFilename, char *out, size_t destlen ); void FS_GetRelativeFilename( const char *currentDirectory, const char *absoluteFilename, char *out, size_t destlen );
extern char fs_gamedir[]; extern char fs_gamedir[];
@ -1098,6 +1099,7 @@ extern cvar_t *com_cameraMode;
extern cvar_t *com_ansiColor; extern cvar_t *com_ansiColor;
extern cvar_t *com_unfocused; extern cvar_t *com_unfocused;
extern cvar_t *com_minimized; extern cvar_t *com_minimized;
extern cvar_t *com_homepath;
extern cvar_t *com_altivec; extern cvar_t *com_altivec;
// both client and server must agree to pause // both client and server must agree to pause
@ -1116,6 +1118,7 @@ extern int com_frameTime;
extern int com_frameMsec; extern int com_frameMsec;
extern qboolean com_errorEntered; extern qboolean com_errorEntered;
extern qboolean com_fullyInitialized;
extern fileHandle_t com_journalFile; extern fileHandle_t com_journalFile;
extern fileHandle_t com_journalDataFile; extern fileHandle_t com_journalDataFile;
@ -1299,6 +1302,14 @@ void SV_Frame( int msec );
void SV_PacketEvent( netadr_t from, msg_t *msg ); void SV_PacketEvent( netadr_t from, msg_t *msg );
qboolean SV_GameCommand( void ); qboolean SV_GameCommand( void );
//
// input interface
//
void IN_Init(void* windowData);
void IN_Frame(void);
void IN_Shutdown(void);
void IN_Restart(void);
void Com_Pause(); void Com_Pause();
void Com_Unpause(); void Com_Unpause();
void Com_FakePause(); void Com_FakePause();
@ -1350,10 +1361,10 @@ sysEvent_t Com_GetSystemEvent( void );
void Sys_Init (void); void Sys_Init (void);
// general development dll loading for virtual machine testing // general development dll loading for virtual machine testing
void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...),
intptr_t (QDECL *systemcalls)(intptr_t, ...) );
void Sys_UnloadDll( void *dllHandle ); void Sys_UnloadDll( void *dllHandle );
qboolean Sys_DllExtension(const char* name);
void Sys_UnloadGame( void ); void Sys_UnloadGame( void );
void *Sys_GetGameAPI( void *parms ); void *Sys_GetGameAPI( void *parms );
@ -1369,7 +1380,7 @@ void *Sys_GetBotLibAPI( void *parms );
char *Sys_GetCurrentUser( void ); char *Sys_GetCurrentUser( void );
void QDECL SyScriptError( const char *error, ...) __attribute__ ((format (printf, 1, 2))); void QDECL Sys_Error( const char *error, ...) __attribute__ ((format (printf, 1, 2)));
void Sys_Quit (void); void Sys_Quit (void);
char *Sys_GetClipboardData( void ); // note that this isn't journaled... char *Sys_GetClipboardData( void ); // note that this isn't journaled...
@ -1399,7 +1410,7 @@ qboolean Sys_StringToAdr( const char *s, netadr_t *a );
qboolean Sys_IsLANAddress (netadr_t adr); qboolean Sys_IsLANAddress (netadr_t adr);
void Sys_ShowIP(void); void Sys_ShowIP(void);
void Sys_Mkdir( const char *path ); qboolean Sys_Mkdir( const char *path );
char *Sys_Cwd( void ); char *Sys_Cwd( void );
void Sys_SetDefaultInstallPath(const char *path); void Sys_SetDefaultInstallPath(const char *path);
char *Sys_DefaultInstallPath( void ); char *Sys_DefaultInstallPath( void );

View file

@ -26,16 +26,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MAX_LOG 32768 #define MAX_LOG 32768
static char consoleLog[ MAX_LOG ]; static char consoleLog[ MAX_LOG ];
static size_t writePos = 0; static unsigned int writePos = 0;
static size_t readPos = 0; static unsigned int readPos = 0;
/* /*
================== ==================
CON_LogSize CON_LogSize
================== ==================
*/ */
size_t CON_LogSize( void ) unsigned int CON_LogSize( void )
{ {
if( readPos <= writePos ) if( readPos <= writePos )
return writePos - readPos; return writePos - readPos;
@ -48,7 +48,7 @@ size_t CON_LogSize( void )
CON_LogFree CON_LogFree
================== ==================
*/ */
static size_t CON_LogFree( void ) static unsigned int CON_LogFree( void )
{ {
return MAX_LOG - CON_LogSize( ) - 1; return MAX_LOG - CON_LogSize( ) - 1;
} }
@ -58,11 +58,11 @@ static size_t CON_LogFree( void )
CON_LogWrite CON_LogWrite
================== ==================
*/ */
size_t CON_LogWrite( const char *in ) unsigned int CON_LogWrite( const char *in )
{ {
size_t length = strlen( in ); unsigned int length = (unsigned int)strlen( in );
size_t firstChunk; unsigned int firstChunk;
size_t secondChunk; unsigned int secondChunk;
while( CON_LogFree( ) < length && CON_LogSize( ) > 0 ) while( CON_LogFree( ) < length && CON_LogSize( ) > 0 )
{ {
@ -101,10 +101,10 @@ size_t CON_LogWrite( const char *in )
CON_LogRead CON_LogRead
================== ==================
*/ */
size_t CON_LogRead( char *out, size_t outSize ) unsigned int CON_LogRead( char *out, unsigned int outSize )
{ {
size_t firstChunk; unsigned int firstChunk;
size_t secondChunk; unsigned int secondChunk;
if( CON_LogSize( ) < outSize ) if( CON_LogSize( ) < outSize )
outSize = CON_LogSize( ); outSize = CON_LogSize( );
@ -121,7 +121,7 @@ size_t CON_LogRead( char *out, size_t outSize )
} }
Com_Memcpy( out, consoleLog + readPos, firstChunk ); Com_Memcpy( out, consoleLog + readPos, firstChunk );
Com_Memcpy( out + firstChunk, out, secondChunk ); Com_Memcpy( out + firstChunk, consoleLog, secondChunk );
readPos = ( readPos + outSize ) % MAX_LOG; readPos = ( readPos + outSize ) % MAX_LOG;

View file

@ -24,6 +24,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/qcommon.h" #include "../qcommon/qcommon.h"
#include "sys_local.h" #include "sys_local.h"
#ifndef DEDICATED
#include "../client/client.h"
#endif
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <termios.h> #include <termios.h>
@ -40,9 +44,12 @@ called before and after a stdout or stderr output
============================================================= =============================================================
*/ */
extern qboolean stdinIsATTY;
static qboolean stdin_active;
// general flag to tell about tty console mode // general flag to tell about tty console mode
static qboolean ttycon_on = qfalse; static qboolean ttycon_on = qfalse;
static int ttycon_hide = 0; static int ttycon_hide = 0;
static int ttycon_show_overdue = 0;
// some key codes that the terminal may be using, initialised on start up // some key codes that the terminal may be using, initialised on start up
static int TTY_erase; static int TTY_erase;
@ -58,19 +65,13 @@ static field_t TTY_con;
static field_t ttyEditLines[ CON_HISTORY ]; static field_t ttyEditLines[ CON_HISTORY ];
static int hist_current = -1, hist_count = 0; static int hist_current = -1, hist_count = 0;
/* #ifndef DEDICATED
================== // Don't use "]" as it would be the same as in-game console,
CON_FlushIn // this makes it clear where input came from.
#define TTY_CONSOLE_PROMPT "tty]"
Flush stdin, I suspect some terminals are sending a LOT of shit #else
FIXME relevant? #define TTY_CONSOLE_PROMPT "]"
================== #endif
*/
static void CON_FlushIn( void )
{
char key;
while (read(0, &key, 1)!=-1);
}
/* /*
================== ==================
@ -86,12 +87,14 @@ send "\b \b"
static void CON_Back( void ) static void CON_Back( void )
{ {
char key; char key;
size_t UNUSED_VAR size;
key = '\b'; key = '\b';
write(1, &key, 1); size = write(STDOUT_FILENO, &key, 1);
key = ' '; key = ' ';
write(1, &key, 1); size = write(STDOUT_FILENO, &key, 1);
key = '\b'; key = '\b';
write(1, &key, 1); size = write(STDOUT_FILENO, &key, 1);
} }
/* /*
@ -119,7 +122,10 @@ static void CON_Hide( void )
CON_Back(); CON_Back();
} }
} }
CON_Back(); // Delete "]" // Delete prompt
for (i = strlen(TTY_CONSOLE_PROMPT); i > 0; i--) {
CON_Back();
}
ttycon_hide++; ttycon_hide++;
} }
} }
@ -142,12 +148,13 @@ static void CON_Show( void )
ttycon_hide--; ttycon_hide--;
if (ttycon_hide == 0) if (ttycon_hide == 0)
{ {
write( 1, "]", 1 ); size_t UNUSED_VAR size;
size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT));
if (TTY_con.cursor) if (TTY_con.cursor)
{ {
for (i=0; i<TTY_con.cursor; i++) for (i=0; i<TTY_con.cursor; i++)
{ {
write(1, TTY_con.buffer+i, 1); size = write(STDOUT_FILENO, TTY_con.buffer+i, 1);
} }
} }
} }
@ -165,12 +172,12 @@ void CON_Shutdown( void )
{ {
if (ttycon_on) if (ttycon_on)
{ {
CON_Back(); // Delete "]" CON_Hide();
tcsetattr (0, TCSADRAIN, &TTY_tc); tcsetattr (STDIN_FILENO, TCSADRAIN, &TTY_tc);
} }
// Restore blocking to stdin reads // Restore blocking to stdin reads
fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) & ~O_NONBLOCK ); fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
} }
/* /*
@ -181,6 +188,11 @@ Hist_Add
void Hist_Add(field_t *field) void Hist_Add(field_t *field)
{ {
int i; int i;
// Don't save blank lines in history.
if (!field->cursor)
return;
assert(hist_count <= CON_HISTORY); assert(hist_count <= CON_HISTORY);
assert(hist_count >= 0); assert(hist_count >= 0);
assert(hist_current >= -1); assert(hist_current >= -1);
@ -241,6 +253,19 @@ field_t *Hist_Next( void )
return &(ttyEditLines[hist_current]); return &(ttyEditLines[hist_current]);
} }
/*
==================
CON_SigCont
Reinitialize console input after receiving SIGCONT, as on Linux the terminal seems to lose all
set attributes if user did CTRL+Z and then does fg again.
==================
*/
void CON_SigCont(int signum)
{
CON_Init();
}
/* /*
================== ==================
CON_Init CON_Init
@ -257,18 +282,22 @@ void CON_Init( void )
signal(SIGTTIN, SIG_IGN); signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN); signal(SIGTTOU, SIG_IGN);
// Make stdin reads non-blocking // If SIGCONT is received, reinitialize console
fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NONBLOCK ); signal(SIGCONT, CON_SigCont);
if (isatty(STDIN_FILENO)!=1) // Make stdin reads non-blocking
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK );
if (!stdinIsATTY)
{ {
Com_Printf( "stdin is not a tty, tty console mode disabled\n"); Com_Printf("tty console mode disabled\n");
ttycon_on = qfalse; ttycon_on = qfalse;
stdin_active = qtrue;
return; return;
} }
Field_Clear(&TTY_con); Field_Clear(&TTY_con);
tcgetattr (0, &TTY_tc); tcgetattr (STDIN_FILENO, &TTY_tc);
TTY_erase = TTY_tc.c_cc[VERASE]; TTY_erase = TTY_tc.c_cc[VERASE];
TTY_eof = TTY_tc.c_cc[VEOF]; TTY_eof = TTY_tc.c_cc[VEOF];
tc = TTY_tc; tc = TTY_tc;
@ -279,8 +308,7 @@ void CON_Init( void )
characters EOF, EOL, EOL2, ERASE, KILL, REPRINT, characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
STATUS, and WERASE, and buffers by lines. STATUS, and WERASE, and buffers by lines.
ISIG: when any of the characters INTR, QUIT, SUSP, or ISIG: when any of the characters INTR, QUIT, SUSP, or
DSUSP are received, generate the corresponding sig­ DSUSP are received, generate the corresponding signal
nal
*/ */
tc.c_lflag &= ~(ECHO | ICANON); tc.c_lflag &= ~(ECHO | ICANON);
@ -291,8 +319,10 @@ void CON_Init( void )
tc.c_iflag &= ~(ISTRIP | INPCK); tc.c_iflag &= ~(ISTRIP | INPCK);
tc.c_cc[VMIN] = 1; tc.c_cc[VMIN] = 1;
tc.c_cc[VTIME] = 0; tc.c_cc[VTIME] = 0;
tcsetattr (0, TCSADRAIN, &tc); tcsetattr (STDIN_FILENO, TCSADRAIN, &tc);
ttycon_on = qtrue; ttycon_on = qtrue;
ttycon_hide = 1; // Mark as hidden, so prompt is shown in CON_Show
CON_Show();
} }
/* /*
@ -303,14 +333,15 @@ CON_Input
char *CON_Input( void ) char *CON_Input( void )
{ {
// we use this when sending back commands // we use this when sending back commands
static char text[256]; static char text[MAX_EDIT_LINE];
int avail; int avail;
char key; char key;
field_t *history; field_t *history;
size_t UNUSED_VAR size;
if( ttycon_on ) if(ttycon_on)
{ {
avail = read(0, &key, 1); avail = read(STDIN_FILENO, &key, 1);
if (avail != -1) if (avail != -1)
{ {
// we have something // we have something
@ -331,13 +362,43 @@ char *CON_Input( void )
{ {
if (key == '\n') if (key == '\n')
{ {
#ifndef DEDICATED
// if not in the game explicitly prepend a slash if needed
if (clc.state != CA_ACTIVE && con_autochat->integer && TTY_con.cursor &&
TTY_con.buffer[0] != '/' && TTY_con.buffer[0] != '\\')
{
memmove(TTY_con.buffer + 1, TTY_con.buffer, sizeof(TTY_con.buffer) - 1);
TTY_con.buffer[0] = '\\';
TTY_con.cursor++;
}
if (TTY_con.buffer[0] == '/' || TTY_con.buffer[0] == '\\') {
Q_strncpyz(text, TTY_con.buffer + 1, sizeof(text));
} else if (TTY_con.cursor) {
if (con_autochat->integer) {
Com_sprintf(text, sizeof(text), "cmd say %s", TTY_con.buffer);
} else {
Q_strncpyz(text, TTY_con.buffer, sizeof(text));
}
} else {
text[0] = '\0';
}
// push it in history // push it in history
Hist_Add(&TTY_con); Hist_Add(&TTY_con);
strcpy(text, TTY_con.buffer); CON_Hide();
Com_Printf("%s%s\n", TTY_CONSOLE_PROMPT, TTY_con.buffer);
Field_Clear(&TTY_con);
CON_Show();
#else
// push it in history
Hist_Add(&TTY_con);
Q_strncpyz(text, TTY_con.buffer, sizeof(text));
Field_Clear(&TTY_con); Field_Clear(&TTY_con);
key = '\n'; key = '\n';
write(1, &key, 1); size = write(STDOUT_FILENO, &key, 1);
write( 1, "]", 1 ); size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT));
#endif
return text; return text;
} }
if (key == '\t') if (key == '\t')
@ -347,13 +408,13 @@ char *CON_Input( void )
CON_Show(); CON_Show();
return NULL; return NULL;
} }
avail = read(0, &key, 1); avail = read(STDIN_FILENO, &key, 1);
if (avail != -1) if (avail != -1)
{ {
// VT 100 keys // VT 100 keys
if (key == '[' || key == 'O') if (key == '[' || key == 'O')
{ {
avail = read(0, &key, 1); avail = read(STDIN_FILENO, &key, 1);
if (avail != -1) if (avail != -1)
{ {
switch (key) switch (key)
@ -366,7 +427,7 @@ char *CON_Input( void )
TTY_con = *history; TTY_con = *history;
CON_Show(); CON_Show();
} }
CON_FlushIn(); tcflush(STDIN_FILENO, TCIFLUSH);
return NULL; return NULL;
break; break;
case 'B': case 'B':
@ -380,7 +441,7 @@ char *CON_Input( void )
Field_Clear(&TTY_con); Field_Clear(&TTY_con);
} }
CON_Show(); CON_Show();
CON_FlushIn(); tcflush(STDIN_FILENO, TCIFLUSH);
return NULL; return NULL;
break; break;
case 'C': case 'C':
@ -392,41 +453,34 @@ char *CON_Input( void )
} }
} }
Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase); Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase);
CON_FlushIn(); tcflush(STDIN_FILENO, TCIFLUSH);
return NULL; return NULL;
} }
if (TTY_con.cursor >= sizeof(text) - 1)
return NULL;
// push regular character // push regular character
TTY_con.buffer[TTY_con.cursor] = key; TTY_con.buffer[TTY_con.cursor] = key;
TTY_con.cursor++; TTY_con.cursor++; // next char will always be '\0'
// print the current line (this is differential) // print the current line (this is differential)
write(1, &key, 1); size = write(STDOUT_FILENO, &key, 1);
} }
return NULL; return NULL;
} }
else else if (stdin_active)
{ {
int len; int len;
fd_set fdset; fd_set fdset;
struct timeval timeout; struct timeval timeout;
static qboolean stdin_active;
if (!com_dedicated || !com_dedicated->value)
return NULL;
if (!stdin_active)
return NULL;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(0, &fdset); // stdin FD_SET(STDIN_FILENO, &fdset); // stdin
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 0; timeout.tv_usec = 0;
if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) if(select (STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(STDIN_FILENO, &fdset))
{
return NULL; return NULL;
}
len = read (0, text, sizeof(text)); len = read(STDIN_FILENO, text, sizeof(text));
if (len == 0) if (len == 0)
{ // eof! { // eof!
stdin_active = qfalse; stdin_active = qfalse;
@ -439,6 +493,7 @@ char *CON_Input( void )
return text; return text;
} }
return NULL;
} }
/* /*
@ -448,6 +503,9 @@ CON_Print
*/ */
void CON_Print( const char *msg ) void CON_Print( const char *msg )
{ {
if (!msg[0])
return;
CON_Hide( ); CON_Hide( );
if( com_ansiColor && com_ansiColor->integer ) if( com_ansiColor && com_ansiColor->integer )
@ -455,5 +513,25 @@ void CON_Print( const char *msg )
else else
fputs( msg, stderr ); fputs( msg, stderr );
CON_Show( ); if (!ttycon_on) {
// CON_Hide didn't do anything.
return;
}
// Only print prompt when msg ends with a newline, otherwise the console
// might get garbled when output does not fit on one line.
if (msg[strlen(msg) - 1] == '\n') {
CON_Show();
// Run CON_Show the number of times it was deferred.
while (ttycon_show_overdue > 0) {
CON_Show();
ttycon_show_overdue--;
}
}
else
{
// Defer calling CON_Show
ttycon_show_overdue++;
}
} }

View file

@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define QCONSOLE_HISTORY 32 #define QCONSOLE_HISTORY 32
static WORD qconsole_attrib; static WORD qconsole_attrib;
static WORD qconsole_backgroundAttrib;
// saved console status // saved console status
static DWORD qconsole_orig_mode; static DWORD qconsole_orig_mode;
@ -36,15 +37,50 @@ static CONSOLE_CURSOR_INFO qconsole_orig_cursorinfo;
// cmd history // cmd history
static char qconsole_history[ QCONSOLE_HISTORY ][ MAX_EDIT_LINE ]; static char qconsole_history[ QCONSOLE_HISTORY ][ MAX_EDIT_LINE ];
static int qconsole_history_pos = -1; static int qconsole_history_pos = -1;
static int qconsole_history_lines = 0;
static int qconsole_history_oldest = 0; static int qconsole_history_oldest = 0;
// current edit buffer // current edit buffer
static char qconsole_line[ MAX_EDIT_LINE ]; static char qconsole_line[ MAX_EDIT_LINE ];
static size_t qconsole_linelen = 0; static int qconsole_linelen = 0;
static qboolean qconsole_drawinput = qtrue;
static int qconsole_cursor;
static HANDLE qconsole_hout; static HANDLE qconsole_hout;
static HANDLE qconsole_hin; static HANDLE qconsole_hin;
/*
==================
CON_ColorCharToAttrib
Convert Quake color character to Windows text attrib
==================
*/
static WORD CON_ColorCharToAttrib( char color ) {
WORD attrib;
if ( color == COLOR_WHITE )
{
// use console's foreground and background colors
attrib = qconsole_attrib;
}
else
{
float *rgba = g_color_table[ ColorIndex( color ) ];
// set foreground color
attrib = ( rgba[0] >= 0.5 ? FOREGROUND_RED : 0 ) |
( rgba[1] >= 0.5 ? FOREGROUND_GREEN : 0 ) |
( rgba[2] >= 0.5 ? FOREGROUND_BLUE : 0 ) |
( rgba[3] >= 0.5 ? FOREGROUND_INTENSITY : 0 );
// use console's background color
attrib |= qconsole_backgroundAttrib;
}
return attrib;
}
/* /*
================== ==================
CON_CtrlHandler CON_CtrlHandler
@ -73,6 +109,9 @@ static void CON_HistAdd( void )
Q_strncpyz( qconsole_history[ qconsole_history_oldest ], qconsole_line, Q_strncpyz( qconsole_history[ qconsole_history_oldest ], qconsole_line,
sizeof( qconsole_history[ qconsole_history_oldest ] ) ); sizeof( qconsole_history[ qconsole_history_oldest ] ) );
if( qconsole_history_lines < QCONSOLE_HISTORY )
qconsole_history_lines++;
if( qconsole_history_oldest >= QCONSOLE_HISTORY - 1 ) if( qconsole_history_oldest >= QCONSOLE_HISTORY - 1 )
qconsole_history_oldest = 0; qconsole_history_oldest = 0;
else else
@ -94,13 +133,14 @@ static void CON_HistPrev( void )
( QCONSOLE_HISTORY - 1 ) : ( qconsole_history_pos - 1 ); ( QCONSOLE_HISTORY - 1 ) : ( qconsole_history_pos - 1 );
// don' t allow looping through history // don' t allow looping through history
if( pos == qconsole_history_oldest ) if( pos == qconsole_history_oldest || pos >= qconsole_history_lines )
return; return;
qconsole_history_pos = pos; qconsole_history_pos = pos;
Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ], Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ],
sizeof( qconsole_line ) ); sizeof( qconsole_line ) );
qconsole_linelen = strlen( qconsole_line ); qconsole_linelen = strlen( qconsole_line );
qconsole_cursor = qconsole_linelen;
} }
/* /*
@ -112,14 +152,20 @@ static void CON_HistNext( void )
{ {
int pos; int pos;
// don' t allow looping through history
if( qconsole_history_pos == qconsole_history_oldest )
return;
pos = ( qconsole_history_pos >= QCONSOLE_HISTORY - 1 ) ? pos = ( qconsole_history_pos >= QCONSOLE_HISTORY - 1 ) ?
0 : ( qconsole_history_pos + 1 ); 0 : ( qconsole_history_pos + 1 );
// clear the edit buffer if they try to advance to a future command // clear the edit buffer if they try to advance to a future command
if( pos == qconsole_history_oldest ) if( pos == qconsole_history_oldest )
{ {
qconsole_history_pos = pos;
qconsole_line[ 0 ] = '\0'; qconsole_line[ 0 ] = '\0';
qconsole_linelen = 0; qconsole_linelen = 0;
qconsole_cursor = qconsole_linelen;
return; return;
} }
@ -127,6 +173,7 @@ static void CON_HistNext( void )
Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ], Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ],
sizeof( qconsole_line ) ); sizeof( qconsole_line ) );
qconsole_linelen = strlen( qconsole_line ); qconsole_linelen = strlen( qconsole_line );
qconsole_cursor = qconsole_linelen;
} }
@ -141,13 +188,15 @@ static void CON_Show( void )
COORD writeSize = { MAX_EDIT_LINE, 1 }; COORD writeSize = { MAX_EDIT_LINE, 1 };
COORD writePos = { 0, 0 }; COORD writePos = { 0, 0 };
SMALL_RECT writeArea = { 0, 0, 0, 0 }; SMALL_RECT writeArea = { 0, 0, 0, 0 };
COORD cursorPos;
int i; int i;
CHAR_INFO line[ MAX_EDIT_LINE ]; CHAR_INFO line[ MAX_EDIT_LINE ];
WORD attrib;
GetConsoleScreenBufferInfo( qconsole_hout, &binfo ); GetConsoleScreenBufferInfo( qconsole_hout, &binfo );
// if we're in the middle of printf, don't bother writing the buffer // if we're in the middle of printf, don't bother writing the buffer
if( binfo.dwCursorPosition.X != 0 ) if( !qconsole_drawinput )
return; return;
writeArea.Left = 0; writeArea.Left = 0;
@ -155,15 +204,23 @@ static void CON_Show( void )
writeArea.Bottom = binfo.dwCursorPosition.Y; writeArea.Bottom = binfo.dwCursorPosition.Y;
writeArea.Right = MAX_EDIT_LINE; writeArea.Right = MAX_EDIT_LINE;
// set color to white
attrib = CON_ColorCharToAttrib( COLOR_WHITE );
// build a space-padded CHAR_INFO array // build a space-padded CHAR_INFO array
for( i = 0; i < MAX_EDIT_LINE; i++ ) for( i = 0; i < MAX_EDIT_LINE; i++ )
{ {
if( i < qconsole_linelen ) if( i < qconsole_linelen )
{
if( i + 1 < qconsole_linelen && Q_IsColorString( qconsole_line + i ) )
attrib = CON_ColorCharToAttrib( *( qconsole_line + i + 1 ) );
line[ i ].Char.AsciiChar = qconsole_line[ i ]; line[ i ].Char.AsciiChar = qconsole_line[ i ];
}
else else
line[ i ].Char.AsciiChar = ' '; line[ i ].Char.AsciiChar = ' ';
line[ i ].Attributes = qconsole_attrib; line[ i ].Attributes = attrib;
} }
if( qconsole_linelen > binfo.srWindow.Right ) if( qconsole_linelen > binfo.srWindow.Right )
@ -177,8 +234,37 @@ static void CON_Show( void )
WriteConsoleOutput( qconsole_hout, line, writeSize, WriteConsoleOutput( qconsole_hout, line, writeSize,
writePos, &writeArea ); writePos, &writeArea );
} }
// set curor position
cursorPos.Y = binfo.dwCursorPosition.Y;
cursorPos.X = qconsole_cursor < qconsole_linelen
? qconsole_cursor
: qconsole_linelen > binfo.srWindow.Right
? binfo.srWindow.Right
: qconsole_linelen;
SetConsoleCursorPosition( qconsole_hout, cursorPos );
} }
/*
==================
CON_Hide
==================
*/
static void CON_Hide( void )
{
int realLen;
realLen = qconsole_linelen;
// remove input line from console output buffer
qconsole_linelen = 0;
CON_Show( );
qconsole_linelen = realLen;
}
/* /*
================== ==================
CON_Shutdown CON_Shutdown
@ -186,8 +272,10 @@ CON_Shutdown
*/ */
void CON_Shutdown( void ) void CON_Shutdown( void )
{ {
CON_Hide( );
SetConsoleMode( qconsole_hin, qconsole_orig_mode ); SetConsoleMode( qconsole_hin, qconsole_orig_mode );
SetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo ); SetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo );
SetConsoleTextAttribute( qconsole_hout, qconsole_attrib );
CloseHandle( qconsole_hout ); CloseHandle( qconsole_hout );
CloseHandle( qconsole_hin ); CloseHandle( qconsole_hin );
} }
@ -199,7 +287,6 @@ CON_Init
*/ */
void CON_Init( void ) void CON_Init( void )
{ {
CONSOLE_CURSOR_INFO curs;
CONSOLE_SCREEN_BUFFER_INFO info; CONSOLE_SCREEN_BUFFER_INFO info;
int i; int i;
@ -224,18 +311,16 @@ void CON_Init( void )
GetConsoleScreenBufferInfo( qconsole_hout, &info ); GetConsoleScreenBufferInfo( qconsole_hout, &info );
qconsole_attrib = info.wAttributes; qconsole_attrib = info.wAttributes;
qconsole_backgroundAttrib = qconsole_attrib & (BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED|BACKGROUND_INTENSITY);
SetConsoleTitle(CLIENT_WINDOW_TITLE " Dedicated Server Console"); SetConsoleTitle(CLIENT_WINDOW_TITLE " Dedicated Server Console");
// make cursor invisible
GetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo );
curs.dwSize = 1;
curs.bVisible = FALSE;
SetConsoleCursorInfo( qconsole_hout, &curs );
// initialize history // initialize history
for( i = 0; i < QCONSOLE_HISTORY; i++ ) for( i = 0; i < QCONSOLE_HISTORY; i++ )
qconsole_history[ i ][ 0 ] = '\0'; qconsole_history[ i ][ 0 ] = '\0';
// set text color to white
SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( COLOR_WHITE ) );
} }
/* /*
@ -281,6 +366,7 @@ char *CON_Input( void )
if( key == VK_RETURN ) if( key == VK_RETURN )
{ {
newlinepos = i; newlinepos = i;
qconsole_cursor = 0;
break; break;
} }
else if( key == VK_UP ) else if( key == VK_UP )
@ -293,6 +379,34 @@ char *CON_Input( void )
CON_HistNext(); CON_HistNext();
break; break;
} }
else if( key == VK_LEFT )
{
qconsole_cursor--;
if ( qconsole_cursor < 0 )
{
qconsole_cursor = 0;
}
break;
}
else if( key == VK_RIGHT )
{
qconsole_cursor++;
if ( qconsole_cursor > qconsole_linelen )
{
qconsole_cursor = qconsole_linelen;
}
break;
}
else if( key == VK_HOME )
{
qconsole_cursor = 0;
break;
}
else if( key == VK_END )
{
qconsole_cursor = qconsole_linelen;
break;
}
else if( key == VK_TAB ) else if( key == VK_TAB )
{ {
field_t f; field_t f;
@ -303,6 +417,7 @@ char *CON_Input( void )
Q_strncpyz( qconsole_line, f.buffer, Q_strncpyz( qconsole_line, f.buffer,
sizeof( qconsole_line ) ); sizeof( qconsole_line ) );
qconsole_linelen = strlen( qconsole_line ); qconsole_linelen = strlen( qconsole_line );
qconsole_cursor = qconsole_linelen;
break; break;
} }
@ -312,15 +427,33 @@ char *CON_Input( void )
if( key == VK_BACK ) if( key == VK_BACK )
{ {
size_t pos = ( qconsole_linelen > 0 ) ? if ( qconsole_cursor > 0 )
qconsole_linelen - 1 : 0; {
int newlen = ( qconsole_linelen > 0 ) ? qconsole_linelen - 1 : 0;
if ( qconsole_cursor < qconsole_linelen )
{
memmove( qconsole_line + qconsole_cursor - 1,
qconsole_line + qconsole_cursor,
qconsole_linelen - qconsole_cursor );
}
qconsole_line[ pos ] = '\0'; qconsole_line[ newlen ] = '\0';
qconsole_linelen = pos; qconsole_linelen = newlen;
qconsole_cursor--;
}
} }
else if( c ) else if( c )
{ {
qconsole_line[ qconsole_linelen++ ] = c; if ( qconsole_linelen > qconsole_cursor )
{
memmove( qconsole_line + qconsole_cursor + 1,
qconsole_line + qconsole_cursor,
qconsole_linelen - qconsole_cursor );
}
qconsole_line[ qconsole_cursor++ ] = c;
qconsole_linelen++;
qconsole_line[ qconsole_linelen ] = '\0'; qconsole_line[ qconsole_linelen ] = '\0';
} }
} }
@ -338,15 +471,74 @@ char *CON_Input( void )
return NULL; return NULL;
} }
CON_HistAdd();
Com_Printf( "%s\n", qconsole_line );
qconsole_linelen = 0; qconsole_linelen = 0;
CON_Show(); CON_Show();
CON_HistAdd();
Com_Printf( "%s\n", qconsole_line );
return qconsole_line; return qconsole_line;
} }
/*
=================
CON_WindowsColorPrint
Set text colors based on Q3 color codes
=================
*/
void CON_WindowsColorPrint( const char *msg )
{
static char buffer[ MAXPRINTMSG ];
int length = 0;
while( *msg )
{
qconsole_drawinput = ( *msg == '\n' );
if( Q_IsColorString( msg ) || *msg == '\n' )
{
// First empty the buffer
if( length > 0 )
{
buffer[ length ] = '\0';
fputs( buffer, stderr );
length = 0;
}
if( *msg == '\n' )
{
// Reset color and then add the newline
SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( COLOR_WHITE ) );
fputs( "\n", stderr );
msg++;
}
else
{
// Set the color
SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( *( msg + 1 ) ) );
msg += 2;
}
}
else
{
if( length >= MAXPRINTMSG - 1 )
break;
buffer[ length ] = *msg;
length++;
msg++;
}
}
// Empty anything still left in the buffer
if( length > 0 )
{
buffer[ length ] = '\0';
fputs( buffer, stderr );
}
}
/* /*
================== ==================
CON_Print CON_Print
@ -354,7 +546,9 @@ CON_Print
*/ */
void CON_Print( const char *msg ) void CON_Print( const char *msg )
{ {
fputs( msg, stderr ); CON_Hide( );
CON_WindowsColorPrint( msg );
CON_Show( ); CON_Show( );
} }

View file

@ -0,0 +1,86 @@
/*
The code in this file is in the public domain. The rest of ioquake3
is licensed under the GPLv2. Do not mingle code, please!
*/
#ifdef USE_AUTOUPDATER
# ifndef AUTOUPDATER_BIN
# error The build system should have defined AUTOUPDATER_BIN
# endif
# ifdef _WIN32
# define WIN32_LEAN_AND_MEAN 1
# include <windows.h>
# else
# include <unistd.h>
# endif
# include <stdio.h>
# include <string.h>
#endif
void Sys_LaunchAutoupdater(int argc, char **argv)
{
#ifdef USE_AUTOUPDATER
#ifdef _WIN32
{
/* We don't need the Unix pipe() tapdance here because Windows lets children wait on parent processes. */
PROCESS_INFORMATION procinfo;
STARTUPINFO startinfo;
char cmdline[128];
memset(&procinfo, '\0', sizeof (procinfo));
memset(&startinfo, '\0', sizeof (startinfo));
startinfo.cb = sizeof (startinfo);
sprintf(cmdline, "" AUTOUPDATER_BIN " --waitpid %u", (unsigned int) GetCurrentProcessId());
if (CreateProcessA(AUTOUPDATER_BIN, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startinfo, &procinfo))
{
/* close handles now so child cleans up immediately if nothing to do */
CloseHandle(procinfo.hProcess);
CloseHandle(procinfo.hThread);
}
}
#else
int updater_pipes[2];
if (pipe(updater_pipes) == 0)
{
pid_t pid = fork();
if (pid == -1) /* failure, oh well. */
{
close(updater_pipes[0]);
close(updater_pipes[1]);
}
else if (pid == 0) /* child process */
{
close(updater_pipes[1]); /* don't need write end. */
if (dup2(updater_pipes[0], 3) != -1)
{
char pidstr[64];
char *ptr = strrchr(argv[0], '/');
if (ptr)
*ptr = '\0';
if (chdir(argv[0]) == -1) {
_exit(1); /* oh well. */
}
#ifdef __APPLE__
if (chdir("../..") == -1) { /* put this at base of app bundle so paths make sense later. */
_exit(1); /* oh well. */
}
#endif
snprintf(pidstr, sizeof (pidstr), "%lld", (long long) getppid());
execl(AUTOUPDATER_BIN, AUTOUPDATER_BIN, "--waitpid", pidstr, NULL);
}
_exit(0); /* oh well. */
}
else /* parent process */
{
/* leave the write end open until we terminate so updater can block on it. */
close(updater_pipes[0]);
}
}
#endif
#endif
(void) argc; (void) argv; /* possibly unused. Pacify compilers. */
}

View file

@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
#pragma once
#ifdef DEDICATED #ifdef DEDICATED
# ifdef _WIN32 # ifdef _WIN32
# include <windows.h> # include <windows.h>
@ -33,12 +35,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# define Sys_UnloadLibrary(h) dlclose(h) # define Sys_UnloadLibrary(h) dlclose(h)
# define Sys_LoadFunction(h,fn) dlsym(h,fn) # define Sys_LoadFunction(h,fn) dlsym(h,fn)
# define Sys_LibraryError() dlerror() # define Sys_LibraryError() dlerror()
#endif # endif
#else #else
# include "SDL.h" # ifdef USE_LOCAL_HEADERS
# include "SDL_loadso.h" # include "SDL.h"
# include "SDL_loadso.h"
# else
# include <SDL.h>
# include <SDL_loadso.h>
# endif
# define Sys_LoadLibrary(f) SDL_LoadObject(f) # define Sys_LoadLibrary(f) SDL_LoadObject(f)
# define Sys_UnloadLibrary(h) SDL_UnloadObject(h) # define Sys_UnloadLibrary(h) SDL_UnloadObject(h)
# define Sys_LoadFunction(h,fn) SDL_LoadFunction(h,fn) # define Sys_LoadFunction(h,fn) SDL_LoadFunction(h,fn)
# define Sys_LibraryError() SDL_GetError() # define Sys_LibraryError() SDL_GetError()
#endif #endif
void * QDECL Sys_LoadDll(const char *name, qboolean useSystemLib);

View file

@ -23,20 +23,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/q_shared.h" #include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h" #include "../qcommon/qcommon.h"
#ifdef __cplusplus #ifndef DEDICATED
extern "C" { #ifdef USE_LOCAL_HEADERS
# include "SDL_version.h"
#else
# include <SDL_version.h>
#endif #endif
// Require a minimum version of SDL // Require a minimum version of SDL
#define MINSDL_MAJOR 1 #define MINSDL_MAJOR 2
#define MINSDL_MINOR 2 #define MINSDL_MINOR 0
#define MINSDL_PATCH 7 #if SDL_VERSION_ATLEAST( 2, 0, 5 )
#define MINSDL_PATCH 5
// Input subsystem #else
void IN_Init( void *windowData ); #define MINSDL_PATCH 0
void IN_Frame( void ); #endif
void IN_Shutdown( void ); #endif
void IN_Restart( void );
// Console // Console
void CON_Shutdown( void ); void CON_Shutdown( void );
@ -44,18 +46,21 @@ void CON_Init( void );
char *CON_Input( void ); char *CON_Input( void );
void CON_Print( const char *message ); void CON_Print( const char *message );
size_t CON_LogSize( void ); unsigned int CON_LogSize( void );
size_t CON_LogWrite( const char *in ); unsigned int CON_LogWrite( const char *in );
size_t CON_LogRead( char *out, size_t outSize ); unsigned int CON_LogRead( char *out, unsigned int outSize );
#ifdef MACOS_X #ifdef __APPLE__
char *Sys_StripAppBundle( char *pwd ); char *Sys_StripAppBundle( char *pwd );
#endif #endif
void Sys_SigHandler( int signal ); void Sys_GLimpSafeInit( void );
void Sys_GLimpInit( void );
void Sys_PlatformInit( void );
void Sys_PlatformExit( void );
void Sys_SigHandler( int signal ) __attribute__ ((noreturn));
void Sys_ErrorDialog( const char *error ); void Sys_ErrorDialog( const char *error );
void Sys_AnsiColorPrint( const char *msg ); void Sys_AnsiColorPrint( const char *msg );
#ifdef __cplusplus int Sys_PID( void );
} qboolean Sys_PIDIsRunning( int pid );
#endif

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/qcommon.h" #include "../qcommon/qcommon.h"
#include "sys_local.h" #include "sys_local.h"
#include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
@ -34,10 +35,24 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <sys/time.h> #include <sys/time.h>
#include <pwd.h> #include <pwd.h>
#include <libgen.h> #include <libgen.h>
#include <fcntl.h>
#include <fenv.h>
#include <sys/wait.h>
qboolean stdinIsATTY;
// Used to determine where to store user-specific files // Used to determine where to store user-specific files
static char homePath[ MAX_OSPATH ] = { 0 }; static char homePath[ MAX_OSPATH ] = { 0 };
// Used to store the Steam Quake 3 installation path
static char steamPath[ MAX_OSPATH ] = { 0 };
// Used to store the GOG Quake 3 installation path
static char gogPath[ MAX_OSPATH ] = { 0 };
// Used to store the Microsoft Store Quake 3 installation path
static char microsoftStorePath[MAX_OSPATH] = { 0 };
/* /*
================== ==================
Sys_DefaultHomePath Sys_DefaultHomePath
@ -47,30 +62,79 @@ char *Sys_DefaultHomePath(void)
{ {
char *p; char *p;
if( !*homePath ) if( !*homePath && com_homepath != NULL )
{ {
if( ( p = getenv( "HOME" ) ) != NULL ) if( ( p = getenv( "HOME" ) ) != NULL )
{ {
Q_strncpyz( homePath, p, sizeof( homePath ) ); Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP);
#ifdef MACOS_X #ifdef __APPLE__
Q_strcat( homePath, sizeof( homePath ), "/Library/Application Support/OpenMoHAA" ); Q_strcat(homePath, sizeof(homePath),
"Library/Application Support/");
if(com_homepath->string[0])
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
else
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_MACOSX);
#else #else
Q_strcat( homePath, sizeof( homePath ), "/.openmohaa" ); if(com_homepath->string[0])
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
else
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_UNIX);
#endif #endif
if( mkdir( homePath, 0777 ) )
{
if( errno != EEXIST )
{
Com_Error( "Unable to create directory \"%s\", error is %s(%d)\n",
homePath, strerror( errno ), errno );
}
}
} }
} }
return homePath; return homePath;
} }
/*
================
Sys_SteamPath
================
*/
char *Sys_SteamPath( void )
{
// Disabled since Steam doesn't let you install Quake 3 on Mac/Linux
#if 0 //#ifdef STEAMPATH_NAME
char *p;
if( ( p = getenv( "HOME" ) ) != NULL )
{
#ifdef __APPLE__
char *steamPathEnd = "/Library/Application Support/Steam/SteamApps/common/" STEAMPATH_NAME;
#else
char *steamPathEnd = "/.steam/steam/SteamApps/common/" STEAMPATH_NAME;
#endif
Com_sprintf(steamPath, sizeof(steamPath), "%s%s", p, steamPathEnd);
}
#endif
return steamPath;
}
/*
================
Sys_GogPath
================
*/
char *Sys_GogPath( void )
{
// GOG also doesn't let you install Quake 3 on Mac/Linux
return gogPath;
}
/*
================
Sys_MicrosoftStorePath
================
*/
char* Sys_MicrosoftStorePath(void)
{
// Microsoft Store doesn't exist on Mac/Linux
return microsoftStorePath;
}
/* /*
================ ================
Sys_Milliseconds Sys_Milliseconds
@ -78,8 +142,7 @@ Sys_Milliseconds
*/ */
/* base time in seconds, that's our origin /* base time in seconds, that's our origin
timeval:tv_sec is an int: timeval:tv_sec is an int:
assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038 assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038 */
using unsigned long data type to work right with Sys_XTimeToSysTime */
unsigned long sys_timeBase = 0; unsigned long sys_timeBase = 0;
/* current time in ms, using sys_timeBase as origin /* current time in ms, using sys_timeBase as origin
NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
@ -104,31 +167,6 @@ int Sys_Milliseconds (void)
return curtime; return curtime;
} }
#if !id386
/*
==================
fastftol
==================
*/
long fastftol( float f )
{
return (long)f;
}
/*
==================
Sys_SnapVector
==================
*/
void Sys_SnapVector( float *v )
{
v[0] = rint(v[0]);
v[1] = rint(v[1]);
v[2] = rint(v[2]);
}
#endif
/* /*
================== ==================
Sys_RandomBytes Sys_RandomBytes
@ -142,7 +180,9 @@ qboolean Sys_RandomBytes( byte *string, int len )
if( !fp ) if( !fp )
return qfalse; return qfalse;
if( !fread( string, sizeof( byte ), len, fp ) ) setvbuf( fp, NULL, _IONBF, 0 ); // don't buffer reads from /dev/urandom
if( fread( string, sizeof( byte ), len, fp ) != len )
{ {
fclose( fp ); fclose( fp );
return qfalse; return qfalse;
@ -167,16 +207,6 @@ char *Sys_GetCurrentUser( void )
return p->pw_name; return p->pw_name;
} }
/*
==================
Sys_GetClipboardData
==================
*/
char *Sys_GetClipboardData(void)
{
return NULL;
}
#define MEM_THRESHOLD 96*1024*1024 #define MEM_THRESHOLD 96*1024*1024
/* /*
@ -211,14 +241,64 @@ const char *Sys_Dirname( char *path )
return dirname( path ); return dirname( path );
} }
/*
==============
Sys_FOpen
==============
*/
FILE *Sys_FOpen( const char *ospath, const char *mode ) {
struct stat buf;
// check if path exists and is a directory
if ( !stat( ospath, &buf ) && S_ISDIR( buf.st_mode ) )
return NULL;
return fopen( ospath, mode );
}
/* /*
================== ==================
Sys_Mkdir Sys_Mkdir
================== ==================
*/ */
void Sys_Mkdir( const char *path ) qboolean Sys_Mkdir( const char *path )
{ {
mkdir( path, 0777 ); int result = mkdir( path, 0750 );
if( result != 0 )
return errno == EEXIST;
return qtrue;
}
/*
==================
Sys_Mkfifo
==================
*/
FILE *Sys_Mkfifo( const char *ospath )
{
FILE *fifo;
int result;
int fn;
struct stat buf;
// if file already exists AND is a pipefile, remove it
if( !stat( ospath, &buf ) && S_ISFIFO( buf.st_mode ) )
FS_Remove( ospath );
result = mkfifo( ospath, 0600 );
if( result != 0 )
return NULL;
fifo = fopen( ospath, "w+" );
if( fifo )
{
fn = fileno( fifo );
fcntl( fn, F_SETFL, O_NONBLOCK );
}
return fifo;
} }
/* /*
@ -230,7 +310,10 @@ char *Sys_Cwd( void )
{ {
static char cwd[MAX_OSPATH]; static char cwd[MAX_OSPATH];
getcwd( cwd, sizeof( cwd ) - 1 ); char *result = getcwd( cwd, sizeof( cwd ) - 1 );
if( result != cwd )
return NULL;
cwd[MAX_OSPATH-1] = 0; cwd[MAX_OSPATH-1] = 0;
return cwd; return cwd;
@ -369,9 +452,9 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
continue; continue;
if (*extension) { if (*extension) {
if ( strlen( d->d_name ) < strlen( extension ) || if ( strlen( d->d_name ) < extLen ||
Q_stricmp( Q_stricmp(
d->d_name + strlen( d->d_name ) - strlen( extension ), d->d_name + strlen( d->d_name ) - extLen,
extension ) ) { extension ) ) {
continue; // didn't match continue; // didn't match
} }
@ -423,59 +506,44 @@ void Sys_FreeFileList( char **list )
Z_Free( list ); Z_Free( list );
} }
#ifdef MACOS_X
/*
=================
Sys_StripAppBundle
Discovers if passed dir is suffixed with the directory structure of a Mac OS X
.app bundle. If it is, the .app directory structure is stripped off the end and
the result is returned. If not, dir is returned untouched.
=================
*/
char *Sys_StripAppBundle( char *dir )
{
static char cwd[MAX_OSPATH];
Q_strncpyz(cwd, dir, sizeof(cwd));
if(strcmp(Sys_Basename(cwd), "MacOS"))
return dir;
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
if(strcmp(Sys_Basename(cwd), "Contents"))
return dir;
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
if(!strstr(Sys_Basename(cwd), ".app"))
return dir;
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
return cwd;
}
#endif // MACOS_X
/* /*
================== ==================
Sys_Sleep Sys_Sleep
Block execution for msec or until input is recieved. Block execution for msec or until input is received.
================== ==================
*/ */
void Sys_Sleep( int msec ) void Sys_Sleep( int msec )
{ {
fd_set fdset; if( msec == 0 )
return;
FD_ZERO(&fdset); if( stdinIsATTY )
FD_SET(fileno(stdin), &fdset);
if( msec < 0 )
{ {
select((fileno(stdin) + 1), &fdset, NULL, NULL, NULL); fd_set fdset;
FD_ZERO(&fdset);
FD_SET(STDIN_FILENO, &fdset);
if( msec < 0 )
{
select(STDIN_FILENO + 1, &fdset, NULL, NULL, NULL);
}
else
{
struct timeval timeout;
timeout.tv_sec = msec/1000;
timeout.tv_usec = (msec%1000)*1000;
select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout);
}
} }
else else
{ {
struct timeval timeout; // With nothing to select() on, we can't wait indefinitely
if( msec < 0 )
msec = 10;
timeout.tv_sec = msec/1000; usleep( msec * 1000 );
timeout.tv_usec = (msec%1000)*1000;
select((fileno(stdin) + 1), &fdset, NULL, NULL, &timeout);
} }
} }
@ -490,21 +558,421 @@ void Sys_ErrorDialog( const char *error )
{ {
char buffer[ 1024 ]; char buffer[ 1024 ];
unsigned int size; unsigned int size;
fileHandle_t f; int f = -1;
const char *homepath = Cvar_VariableString( "fs_homepath" );
const char *gamedir = Cvar_VariableString( "fs_game" );
const char *fileName = "crashlog.txt"; const char *fileName = "crashlog.txt";
char *dirpath = FS_BuildOSPath( homepath, gamedir, "");
char *ospath = FS_BuildOSPath( homepath, gamedir, fileName );
Sys_Print( va( "%s\n", error ) ); Sys_Print( va( "%s\n", error ) );
// Write console log to file #ifndef DEDICATED
f = FS_FOpenFileWrite( fileName ); Sys_Dialog( DT_ERROR, va( "%s. See \"%s\" for details.", error, ospath ), "Error" );
if( !f ) #endif
// Make sure the write path for the crashlog exists...
if(!Sys_Mkdir(homepath))
{
Com_Printf("ERROR: couldn't create path '%s' for crash log.\n", homepath);
return;
}
if(!Sys_Mkdir(dirpath))
{
Com_Printf("ERROR: couldn't create path '%s' for crash log.\n", dirpath);
return;
}
// We might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
// which will come through here, so we don't want to recurse forever by
// calling FS_FOpenFileWrite()...use the Unix system APIs instead.
f = open( ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640 );
if( f == -1 )
{ {
Com_Printf( "ERROR: couldn't open %s\n", fileName ); Com_Printf( "ERROR: couldn't open %s\n", fileName );
return; return;
} }
while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) // We're crashing, so we don't care much if write() or close() fails.
FS_Write( buffer, size, f ); while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) {
if( write( f, buffer, size ) != size ) {
Com_Printf( "ERROR: couldn't fully write to %s\n", fileName );
break;
}
}
FS_FCloseFile( f ); close( f );
}
#ifndef __APPLE__
static char execBuffer[ 1024 ];
static char *execBufferPointer;
static char *execArgv[ 16 ];
static int execArgc;
/*
==============
Sys_ClearExecBuffer
==============
*/
static void Sys_ClearExecBuffer( void )
{
execBufferPointer = execBuffer;
Com_Memset( execArgv, 0, sizeof( execArgv ) );
execArgc = 0;
}
/*
==============
Sys_AppendToExecBuffer
==============
*/
static void Sys_AppendToExecBuffer( const char *text )
{
size_t size = sizeof( execBuffer ) - ( execBufferPointer - execBuffer );
int length = strlen( text ) + 1;
if( length > size || execArgc >= ARRAY_LEN( execArgv ) )
return;
Q_strncpyz( execBufferPointer, text, size );
execArgv[ execArgc++ ] = execBufferPointer;
execBufferPointer += length;
}
/*
==============
Sys_Exec
==============
*/
static int Sys_Exec( void )
{
pid_t pid = fork( );
if( pid < 0 )
return -1;
if( pid )
{
// Parent
int exitCode;
wait( &exitCode );
return WEXITSTATUS( exitCode );
}
else
{
// Child
execvp( execArgv[ 0 ], execArgv );
// Failed to execute
exit( -1 );
return -1;
}
}
/*
==============
Sys_ZenityCommand
==============
*/
static void Sys_ZenityCommand( dialogType_t type, const char *message, const char *title )
{
Sys_ClearExecBuffer( );
Sys_AppendToExecBuffer( "zenity" );
switch( type )
{
default:
case DT_INFO: Sys_AppendToExecBuffer( "--info" ); break;
case DT_WARNING: Sys_AppendToExecBuffer( "--warning" ); break;
case DT_ERROR: Sys_AppendToExecBuffer( "--error" ); break;
case DT_YES_NO:
Sys_AppendToExecBuffer( "--question" );
Sys_AppendToExecBuffer( "--ok-label=Yes" );
Sys_AppendToExecBuffer( "--cancel-label=No" );
break;
case DT_OK_CANCEL:
Sys_AppendToExecBuffer( "--question" );
Sys_AppendToExecBuffer( "--ok-label=OK" );
Sys_AppendToExecBuffer( "--cancel-label=Cancel" );
break;
}
Sys_AppendToExecBuffer( va( "--text=%s", message ) );
Sys_AppendToExecBuffer( va( "--title=%s", title ) );
}
/*
==============
Sys_KdialogCommand
==============
*/
static void Sys_KdialogCommand( dialogType_t type, const char *message, const char *title )
{
Sys_ClearExecBuffer( );
Sys_AppendToExecBuffer( "kdialog" );
switch( type )
{
default:
case DT_INFO: Sys_AppendToExecBuffer( "--msgbox" ); break;
case DT_WARNING: Sys_AppendToExecBuffer( "--sorry" ); break;
case DT_ERROR: Sys_AppendToExecBuffer( "--error" ); break;
case DT_YES_NO: Sys_AppendToExecBuffer( "--warningyesno" ); break;
case DT_OK_CANCEL: Sys_AppendToExecBuffer( "--warningcontinuecancel" ); break;
}
Sys_AppendToExecBuffer( message );
Sys_AppendToExecBuffer( va( "--title=%s", title ) );
}
/*
==============
Sys_XmessageCommand
==============
*/
static void Sys_XmessageCommand( dialogType_t type, const char *message, const char *title )
{
Sys_ClearExecBuffer( );
Sys_AppendToExecBuffer( "xmessage" );
Sys_AppendToExecBuffer( "-buttons" );
switch( type )
{
default: Sys_AppendToExecBuffer( "OK:0" ); break;
case DT_YES_NO: Sys_AppendToExecBuffer( "Yes:0,No:1" ); break;
case DT_OK_CANCEL: Sys_AppendToExecBuffer( "OK:0,Cancel:1" ); break;
}
Sys_AppendToExecBuffer( "-center" );
Sys_AppendToExecBuffer( message );
}
/*
==============
Sys_Dialog
Display a *nix dialog box
==============
*/
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
{
typedef enum
{
NONE = 0,
ZENITY,
KDIALOG,
XMESSAGE,
NUM_DIALOG_PROGRAMS
} dialogCommandType_t;
typedef void (*dialogCommandBuilder_t)( dialogType_t, const char *, const char * );
const char *session = getenv( "DESKTOP_SESSION" );
qboolean tried[ NUM_DIALOG_PROGRAMS ] = { qfalse };
dialogCommandBuilder_t commands[ NUM_DIALOG_PROGRAMS ] = { NULL };
dialogCommandType_t preferredCommandType = NONE;
int i;
commands[ ZENITY ] = &Sys_ZenityCommand;
commands[ KDIALOG ] = &Sys_KdialogCommand;
commands[ XMESSAGE ] = &Sys_XmessageCommand;
// This may not be the best way
if( !Q_stricmp( session, "gnome" ) )
preferredCommandType = ZENITY;
else if( !Q_stricmp( session, "kde" ) )
preferredCommandType = KDIALOG;
for( i = NONE + 1; i < NUM_DIALOG_PROGRAMS; i++ )
{
if( preferredCommandType != NONE && preferredCommandType != i )
continue;
if( !tried[ i ] )
{
int exitCode;
commands[ i ]( type, message, title );
exitCode = Sys_Exec( );
if( exitCode >= 0 )
{
switch( type )
{
case DT_YES_NO: return exitCode ? DR_NO : DR_YES;
case DT_OK_CANCEL: return exitCode ? DR_CANCEL : DR_OK;
default: return DR_OK;
}
}
tried[ i ] = qtrue;
// The preference failed, so start again in order
if( preferredCommandType != NONE )
{
preferredCommandType = NONE;
i = NONE + 1;
}
}
}
Com_DPrintf( S_COLOR_YELLOW "WARNING: failed to show a dialog\n" );
return DR_OK;
}
#endif
/*
==============
Sys_GLimpSafeInit
Unix specific "safe" GL implementation initialisation
==============
*/
void Sys_GLimpSafeInit( void )
{
// NOP
}
/*
==============
Sys_GLimpInit
Unix specific GL implementation initialisation
==============
*/
void Sys_GLimpInit( void )
{
// NOP
}
void Sys_SetFloatEnv(void)
{
// rounding toward nearest
fesetround(FE_TONEAREST);
}
/*
==============
Sys_PlatformInit
Unix specific initialisation
==============
*/
void Sys_PlatformInit( void )
{
const char* term = getenv( "TERM" );
signal( SIGHUP, Sys_SigHandler );
signal( SIGQUIT, Sys_SigHandler );
signal( SIGTRAP, Sys_SigHandler );
signal( SIGABRT, Sys_SigHandler );
signal( SIGBUS, Sys_SigHandler );
Sys_SetFloatEnv();
stdinIsATTY = isatty( STDIN_FILENO ) &&
!( term && ( !strcmp( term, "raw" ) || !strcmp( term, "dumb" ) ) );
}
/*
==============
Sys_PlatformExit
Unix specific deinitialisation
==============
*/
void Sys_PlatformExit( void )
{
}
/*
==============
Sys_SetEnv
set/unset environment variables (empty value removes it)
==============
*/
void Sys_SetEnv(const char *name, const char *value)
{
if(value && *value)
setenv(name, value, 1);
else
unsetenv(name);
}
/*
==============
Sys_PID
==============
*/
int Sys_PID( void )
{
return getpid( );
}
/*
==============
Sys_PIDIsRunning
==============
*/
qboolean Sys_PIDIsRunning( size_t pid )
{
return kill( pid, 0 ) == 0;
}
/*
=================
Sys_DllExtension
Check if filename should be allowed to be loaded as a DLL.
=================
*/
qboolean Sys_DllExtension( const char *name ) {
const char *p;
char c = 0;
if ( COM_CompareExtension( name, DLL_EXT ) ) {
return qtrue;
}
#ifdef __APPLE__
// Allow system frameworks without dylib extensions
// i.e., /System/Library/Frameworks/OpenAL.framework/OpenAL
if ( strncmp( name, "/System/Library/Frameworks/", 27 ) == 0 ) {
return qtrue;
}
#endif
// Check for format of filename.so.1.2.3
p = strstr( name, DLL_EXT "." );
if ( p ) {
p += strlen( DLL_EXT );
// Check if .so is only followed for periods and numbers.
while ( *p ) {
c = *p;
if ( !isdigit( c ) && c != '.' ) {
return qfalse;
}
p++;
}
// Don't allow filename to end in a period. file.so., file.so.0., etc
if ( c != '.' ) {
return qtrue;
}
}
return qfalse;
} }

View file

@ -36,19 +36,60 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <conio.h> #include <conio.h>
#include <wincrypt.h> #include <wincrypt.h>
#include <shlobj.h> #include <shlobj.h>
#include <psapi.h>
#include <float.h>
#ifndef KEY_WOW64_32KEY
#define KEY_WOW64_32KEY 0x0200
#endif
// Used to determine where to store user-specific files // Used to determine where to store user-specific files
static char homePath[ MAX_OSPATH ] = { 0 }; static char homePath[ MAX_OSPATH ] = { 0 };
static char programpath[ MAX_OSPATH ] = { 0 };
// Used to store the Steam Quake 3 installation path
static char steamPath[ MAX_OSPATH ] = { 0 };
// Used to store the GOG Quake 3 installation path
static char gogPath[ MAX_OSPATH ] = { 0 };
// Used to store the Microsoft Store Quake 3 installation path
static char microsoftStorePath[MAX_OSPATH] = { 0 };
#ifndef DEDICATED
static UINT timerResolution = 0;
#endif
/* /*
================ ================
RecoverLostAutodialData Sys_SetFPUCW
Set FPU control word to default value
================ ================
*/ */
void RecoverLostAutodialData( void )
#ifndef _RC_CHOP
// mingw doesn't seem to have these defined :(
#define _MCW_EM 0x0008001fU
#define _MCW_RC 0x00000300U
#define _MCW_PC 0x00030000U
#define _RC_NEAR 0x00000000U
#define _PC_53 0x00010000U
unsigned int _controlfp(unsigned int new, unsigned int mask);
#endif
#define FPUCWMASK1 (_MCW_RC | _MCW_EM)
#define FPUCW (_RC_NEAR | _MCW_EM | _PC_53)
#if idx64
#define FPUCWMASK (FPUCWMASK1)
#else
#define FPUCWMASK (FPUCWMASK1 | _MCW_PC)
#endif
void Sys_SetFloatEnv(void)
{ {
// FIXME: stub _controlfp(FPUCW, FPUCWMASK);
} }
/* /*
@ -60,19 +101,16 @@ char *Sys_DefaultHomePath( void )
{ {
TCHAR szPath[MAX_PATH]; TCHAR szPath[MAX_PATH];
FARPROC qSHGetFolderPath; FARPROC qSHGetFolderPath;
HMODULE shfolder; HMODULE shfolder = LoadLibrary("shfolder.dll");
return NULL; if(shfolder == NULL)
shfolder = LoadLibrary("shfolder.dll");
if( !*homePath )
{ {
if(shfolder == NULL) Com_Printf("Unable to load SHFolder.dll\n");
{ return NULL;
Com_Printf("Unable to load SHFolder.dll\n"); }
return NULL;
}
if(!*homePath && com_homepath)
{
qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA"); qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA");
if(qSHGetFolderPath == NULL) if(qSHGetFolderPath == NULL)
{ {
@ -88,70 +126,148 @@ char *Sys_DefaultHomePath( void )
FreeLibrary(shfolder); FreeLibrary(shfolder);
return NULL; return NULL;
} }
Q_strncpyz( homePath, szPath, sizeof( homePath ) );
Q_strcat( homePath, sizeof( homePath ), "\\OpenMoHAA" ); Com_sprintf(homePath, sizeof(homePath), "%s%c", szPath, PATH_SEP);
FreeLibrary(shfolder);
if( !CreateDirectory( homePath, NULL ) ) if(com_homepath->string[0])
{ Q_strcat(homePath, sizeof(homePath), com_homepath->string);
if( GetLastError() != ERROR_ALREADY_EXISTS ) else
{ Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_WIN);
Com_Printf("Unable to create directory \"%s\"\n", homePath );
return NULL;
}
}
} }
FreeLibrary(shfolder);
return homePath; return homePath;
} }
/* /*
================ ================
SetProgramPath Sys_SteamPath
================ ================
*/ */
void SetProgramPath( const char *path ) char *Sys_SteamPath( void )
{ {
char *p; #if defined(STEAMPATH_NAME) || defined(STEAMPATH_APPID)
HKEY steamRegKey;
DWORD pathLen = MAX_OSPATH;
qboolean finishPath = qfalse;
Q_strncpyz( programpath, path, sizeof( programpath ) ); #ifdef STEAMPATH_APPID
// Assuming Steam is a 32-bit app
if (!steamPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STEAMPATH_APPID, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &steamRegKey))
{
pathLen = MAX_OSPATH;
if (RegQueryValueEx(steamRegKey, "InstallLocation", NULL, NULL, (LPBYTE)steamPath, &pathLen))
steamPath[0] = '\0';
p = strrchr( programpath, '/' ); RegCloseKey(steamRegKey);
if( p ) {
*p = 0;
} }
#endif
#ifdef STEAMPATH_NAME
if (!steamPath[0] && !RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &steamRegKey))
{
pathLen = MAX_OSPATH;
if (RegQueryValueEx(steamRegKey, "SteamPath", NULL, NULL, (LPBYTE)steamPath, &pathLen))
if (RegQueryValueEx(steamRegKey, "InstallPath", NULL, NULL, (LPBYTE)steamPath, &pathLen))
steamPath[0] = '\0';
if (steamPath[0])
finishPath = qtrue;
RegCloseKey(steamRegKey);
}
#endif
if (steamPath[0])
{
if (pathLen == MAX_OSPATH)
pathLen--;
steamPath[pathLen] = '\0';
if (finishPath)
Q_strcat(steamPath, MAX_OSPATH, "\\SteamApps\\common\\" STEAMPATH_NAME );
}
#endif
return steamPath;
} }
/* /*
================ ================
Sys_DefaultBasePath Sys_GogPath
================ ================
*/ */
char *Sys_DefaultBasePath( void ) char *Sys_GogPath( void )
{ {
static char basepath[ 256 ]; #ifdef GOGPATH_ID
HKEY gogRegKey;
DWORD pathLen = MAX_OSPATH;
Q_strncpyz( basepath, programpath, sizeof( basepath ) ); if (!gogPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\GOG.com\\Games\\" GOGPATH_ID, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &gogRegKey))
return basepath; {
pathLen = MAX_OSPATH;
if (RegQueryValueEx(gogRegKey, "PATH", NULL, NULL, (LPBYTE)gogPath, &pathLen))
gogPath[0] = '\0';
RegCloseKey(gogRegKey);
}
if (gogPath[0])
{
if (pathLen == MAX_OSPATH)
pathLen--;
gogPath[pathLen] = '\0';
}
#endif
return gogPath;
} }
/* /*
================ ================
Sys_DefaultUserPath Sys_MicrosoftStorePath
================ ================
*/ */
char *Sys_DefaultUserPath( void ) char* Sys_MicrosoftStorePath(void)
{ {
return Sys_DefaultBasePath(); #ifdef MSSTORE_PATH
} if (!microsoftStorePath[0])
{
TCHAR szPath[MAX_PATH];
FARPROC qSHGetFolderPath;
HMODULE shfolder = LoadLibrary("shfolder.dll");
/* if(shfolder == NULL)
================ {
Sys_DefaultUserPath Com_Printf("Unable to load SHFolder.dll\n");
================ return microsoftStorePath;
*/ }
char *Sys_DefaultOutputPath( void )
{ qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA");
return Sys_DefaultUserPath(); if(qSHGetFolderPath == NULL)
{
Com_Printf("Unable to find SHGetFolderPath in SHFolder.dll\n");
FreeLibrary(shfolder);
return microsoftStorePath;
}
if( !SUCCEEDED( qSHGetFolderPath( NULL, CSIDL_PROGRAM_FILES,
NULL, 0, szPath ) ) )
{
Com_Printf("Unable to detect CSIDL_PROGRAM_FILES\n");
FreeLibrary(shfolder);
return microsoftStorePath;
}
FreeLibrary(shfolder);
// default: C:\Program Files\ModifiableWindowsApps\Quake 3\EN
Com_sprintf(microsoftStorePath, sizeof(microsoftStorePath), "%s%cModifiableWindowsApps%c%s%cEN", szPath, PATH_SEP, PATH_SEP, MSSTORE_PATH, PATH_SEP);
}
#endif
return microsoftStorePath;
} }
/* /*
@ -174,40 +290,6 @@ int Sys_Milliseconds (void)
return sys_curtime; return sys_curtime;
} }
#ifndef __GNUC__ //see snapvectora.s
/*
================
Sys_SnapVector
================
*/
void Sys_SnapVector( float *v )
{
#ifndef _WIN64
int i;
float f;
f = *v;
__asm fld f;
__asm fistp i;
*v = i;
v++;
f = *v;
__asm fld f;
__asm fistp i;
*v = i;
v++;
f = *v;
__asm fld f;
__asm fistp i;
*v = i;
#else
v[ 0 ] = rint( v[ 0 ] );
v[ 1 ] = rint( v[ 1 ] );
v[ 2 ] = rint( v[ 2 ] );
#endif
}
#endif
/* /*
================ ================
Sys_RandomBytes Sys_RandomBytes
@ -252,33 +334,6 @@ char *Sys_GetCurrentUser( void )
return s_userName; return s_userName;
} }
/*
================
Sys_GetClipboardData
================
*/
char *Sys_GetClipboardData( void )
{
char *data = NULL;
char *cliptext;
if ( OpenClipboard( NULL ) != 0 ) {
HANDLE hClipboardData;
if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) {
data = Z_Malloc( GlobalSize( hClipboardData ) + 1 );
Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );
GlobalUnlock( hClipboardData );
strtok( data, "\n\r\b" );
}
}
CloseClipboard();
}
return data;
}
#define MEM_THRESHOLD 96*1024*1024 #define MEM_THRESHOLD 96*1024*1024
/* /*
@ -293,26 +348,6 @@ qboolean Sys_LowPhysicalMemory( void )
return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse; return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
} }
/*
==================
SetNormalThreadPriority
==================
*/
void SetNormalThreadPriority( void )
{
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL );
}
/*
==================
SetBelowNormalThreadPriority
==================
*/
void SetBelowNormalThreadPriority( void )
{
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
}
/* /*
============== ==============
Sys_Basename Sys_Basename
@ -321,7 +356,7 @@ Sys_Basename
const char *Sys_Basename( char *path ) const char *Sys_Basename( char *path )
{ {
static char base[ MAX_OSPATH ] = { 0 }; static char base[ MAX_OSPATH ] = { 0 };
intptr_t length; int length;
length = strlen( path ) - 1; length = strlen( path ) - 1;
@ -351,7 +386,7 @@ Sys_Dirname
const char *Sys_Dirname( char *path ) const char *Sys_Dirname( char *path )
{ {
static char dir[ MAX_OSPATH ] = { 0 }; static char dir[ MAX_OSPATH ] = { 0 };
intptr_t length; int length;
Q_strncpyz( dir, path, sizeof( dir ) ); Q_strncpyz( dir, path, sizeof( dir ) );
length = strlen( dir ) - 1; length = strlen( dir ) - 1;
@ -364,14 +399,48 @@ const char *Sys_Dirname( char *path )
return dir; return dir;
} }
/*
==============
Sys_FOpen
==============
*/
FILE *Sys_FOpen( const char *ospath, const char *mode ) {
size_t length;
// Windows API ignores all trailing spaces and periods which can get around Quake 3 file system restrictions.
length = strlen( ospath );
if ( length == 0 || ospath[length-1] == ' ' || ospath[length-1] == '.' ) {
return NULL;
}
return fopen( ospath, mode );
}
/* /*
============== ==============
Sys_Mkdir Sys_Mkdir
============== ==============
*/ */
void Sys_Mkdir( const char *path ) qboolean Sys_Mkdir( const char *path )
{ {
_mkdir (path); if( !CreateDirectory( path, NULL ) )
{
if( GetLastError( ) != ERROR_ALREADY_EXISTS )
return qfalse;
}
return qtrue;
}
/*
==================
Sys_Mkfifo
Noop on windows because named pipes do not function the same way
==================
*/
FILE *Sys_Mkfifo( const char *ospath )
{
return NULL;
} }
/* /*
@ -403,7 +472,7 @@ DIRECTORY SCANNING
Sys_ListFilteredFiles Sys_ListFilteredFiles
============== ==============
*/ */
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, const char **list, int *numfiles ) void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
{ {
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH]; char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH]; char filename[MAX_OSPATH];
@ -490,9 +559,10 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
char **listCopy; char **listCopy;
char *list[MAX_FOUND_FILES]; char *list[MAX_FOUND_FILES];
struct _finddata_t findinfo; struct _finddata_t findinfo;
intptr_t findhandle; intptr_t findhandle;
int flag; int flag;
int i; int i;
int extLen;
if (filter) { if (filter) {
@ -526,6 +596,8 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
flag = _A_SUBDIR; flag = _A_SUBDIR;
} }
extLen = strlen( extension );
Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension ); Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
// search // search
@ -539,6 +611,14 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
do { do {
if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) { if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
if (*extension) {
if ( strlen( findinfo.name ) < extLen ||
Q_stricmp(
findinfo.name + strlen( findinfo.name ) - extLen,
extension ) ) {
continue; // didn't match
}
}
if ( nfiles == MAX_FOUND_FILES - 1 ) { if ( nfiles == MAX_FOUND_FILES - 1 ) {
break; break;
} }
@ -604,28 +684,39 @@ void Sys_FreeFileList( char **list )
============== ==============
Sys_Sleep Sys_Sleep
Block execution for msec or until input is recieved. Block execution for msec or until input is received.
============== ==============
*/ */
void Sys_Sleep( int msec ) void Sys_Sleep( int msec )
{ {
if( msec == 0 )
return;
#ifdef DEDICATED
if( msec < 0 ) if( msec < 0 )
WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), INFINITE ); WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), INFINITE );
else else
WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), msec ); WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), msec );
#else
// Client Sys_Sleep doesn't support waiting on stdin
if( msec < 0 )
return;
Sleep( msec );
#endif
} }
/* /*
============== ==============
SyScriptErrorDialog Sys_ErrorDialog
Display an error message Display an error message
============== ==============
*/ */
void SyScriptErrorDialog( const char *error ) void Sys_ErrorDialog( const char *error )
{ {
if( MessageBox( NULL, va( "%s. Copy console log to clipboard?", error ), if( Sys_Dialog( DT_YES_NO, va( "%s. Copy console log to clipboard?", error ),
NULL, MB_YESNO|MB_ICONERROR ) == IDYES ) "Error" ) == DR_YES )
{ {
HGLOBAL memoryHandle; HGLOBAL memoryHandle;
char *clipMemory; char *clipMemory;
@ -637,7 +728,7 @@ void SyScriptErrorDialog( const char *error )
{ {
char *p = clipMemory; char *p = clipMemory;
char buffer[ 1024 ]; char buffer[ 1024 ];
size_t size; unsigned int size;
while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 )
{ {
@ -656,39 +747,10 @@ void SyScriptErrorDialog( const char *error )
} }
} }
/*
==============
Sys_CloseMutex
==============
*/
void Sys_CloseMutex( void )
{
// FIXME: stub
}
/*
==============
Sys_ShowConsole
==============
*/
void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
{
// FIXME: stub
}
/*
==============
Sys_PumpMessageLoop
==============
*/
void Sys_PumpMessageLoop( void )
{
// FIXME: stub
}
/* /*
============== ==============
Sys_Dialog Sys_Dialog
Display a win32 dialog box Display a win32 dialog box
============== ==============
*/ */
@ -716,14 +778,185 @@ dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *t
} }
} }
/*
==============
Sys_GLimpSafeInit
Windows specific "safe" GL implementation initialisation
==============
*/
void Sys_GLimpSafeInit( void )
{
}
/*
==============
Sys_GLimpInit
Windows specific GL implementation initialisation
==============
*/
void Sys_GLimpInit( void )
{
}
/*
==============
Sys_PlatformInit
Windows specific initialisation
==============
*/
void Sys_PlatformInit( void )
{
#ifndef DEDICATED
TIMECAPS ptc;
#endif
Sys_SetFloatEnv();
#ifndef DEDICATED
if(timeGetDevCaps(&ptc, sizeof(ptc)) == MMSYSERR_NOERROR)
{
timerResolution = ptc.wPeriodMin;
if(timerResolution > 1)
{
Com_Printf("Warning: Minimum supported timer resolution is %ums "
"on this system, recommended resolution 1ms\n", timerResolution);
}
timeBeginPeriod(timerResolution);
}
else
timerResolution = 0;
#endif
}
/*
==============
Sys_PlatformExit
Windows specific initialisation
==============
*/
void Sys_PlatformExit( void )
{
#ifndef DEDICATED
if(timerResolution)
timeEndPeriod(timerResolution);
#endif
}
/*
==============
Sys_SetEnv
set/unset environment variables (empty value removes it)
==============
*/
void Sys_SetEnv(const char *name, const char *value)
{
if(value)
_putenv(va("%s=%s", name, value));
else
_putenv(va("%s=", name));
}
/*
==============
Sys_PID
==============
*/
int Sys_PID( void )
{
return GetCurrentProcessId( );
}
/*
==============
Sys_PIDIsRunning
==============
*/
qboolean Sys_PIDIsRunning( int pid )
{
DWORD processes[ 1024 ];
DWORD numBytes, numProcesses;
int i;
if( !EnumProcesses( processes, sizeof( processes ), &numBytes ) )
return qfalse; // Assume it's not running
numProcesses = numBytes / sizeof( DWORD );
// Search for the pid
for( i = 0; i < numProcesses; i++ )
{
if( processes[ i ] == pid )
return qtrue;
}
return qfalse;
}
/*
=================
Sys_DllExtension
Check if filename should be allowed to be loaded as a DLL.
=================
*/
qboolean Sys_DllExtension( const char *name ) {
return COM_CompareExtension( name, DLL_EXT );
}
/*
================
RecoverLostAutodialData
================
*/
void RecoverLostAutodialData(void)
{
// FIXME: stub
}
/*
==============
Sys_CloseMutex
==============
*/
void Sys_CloseMutex(void)
{
// FIXME: stub
}
/*
==============
Sys_ShowConsole
==============
*/
void Sys_ShowConsole(int visLevel, qboolean quitOnClose)
{
// FIXME: stub
}
/*
==============
Sys_PumpMessageLoop
==============
*/
void Sys_PumpMessageLoop(void)
{
// FIXME: stub
}
/* /*
============== ==============
SaveRegistryInfo SaveRegistryInfo
============== ==============
*/ */
qboolean SaveRegistryInfo( qboolean user, const char *pszName, void *pvBuf, long lSize ) qboolean SaveRegistryInfo(qboolean user, const char* pszName, void* pvBuf, long lSize)
{ {
STUB_DESC( "not implemented" ); STUB_DESC("not implemented");
return qfalse; return qfalse;
} }
@ -732,9 +965,9 @@ qboolean SaveRegistryInfo( qboolean user, const char *pszName, void *pvBuf, long
LoadRegistryInfo LoadRegistryInfo
============== ==============
*/ */
qboolean LoadRegistryInfo( qboolean user, const char *pszName, void *pvBuf, long *plSize ) qboolean LoadRegistryInfo(qboolean user, const char* pszName, void* pvBuf, long* plSize)
{ {
STUB_DESC( "not implemented" ); STUB_DESC("not implemented");
return qfalse; return qfalse;
} }
@ -743,9 +976,9 @@ qboolean LoadRegistryInfo( qboolean user, const char *pszName, void *pvBuf, long
IsFirstRun IsFirstRun
============== ==============
*/ */
qboolean IsFirstRun( void ) qboolean IsFirstRun(void)
{ {
STUB_DESC( "wtf" ); STUB_DESC("wtf");
return qfalse; return qfalse;
} }
@ -754,9 +987,9 @@ qboolean IsFirstRun( void )
IsNewConfig IsNewConfig
============== ==============
*/ */
qboolean IsNewConfig( void ) qboolean IsNewConfig(void)
{ {
STUB_DESC( "wtf" ); STUB_DESC("wtf");
return qfalse; return qfalse;
} }
@ -765,9 +998,9 @@ qboolean IsNewConfig( void )
IsSafeMode IsSafeMode
============== ==============
*/ */
qboolean IsSafeMode( void ) qboolean IsSafeMode(void)
{ {
STUB_DESC( "wtf" ); STUB_DESC("wtf");
return qfalse; return qfalse;
} }
@ -776,7 +1009,7 @@ qboolean IsSafeMode( void )
ClearNewConfigFlag ClearNewConfigFlag
============== ==============
*/ */
void ClearNewConfigFlag( void ) void ClearNewConfigFlag(void)
{ {
} }
@ -785,7 +1018,7 @@ void ClearNewConfigFlag( void )
Sys_GetWholeClipboard Sys_GetWholeClipboard
============== ==============
*/ */
const char *Sys_GetWholeClipboard( void ) const char* Sys_GetWholeClipboard(void)
{ {
return NULL; return NULL;
} }
@ -795,6 +1028,26 @@ const char *Sys_GetWholeClipboard( void )
Sys_SetClipboard Sys_SetClipboard
============== ==============
*/ */
void Sys_SetClipboard( const char *contents ) void Sys_SetClipboard(const char* contents)
{ {
} }
/*
==================
SetNormalThreadPriority
==================
*/
void SetNormalThreadPriority(void)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
}
/*
==================
SetBelowNormalThreadPriority
==================
*/
void SetBelowNormalThreadPriority(void)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
}