/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
RTCW MP Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
RTCW MP Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RTCW MP Source Code. If not, see .
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "../game/q_shared.h"
#include "../qcommon/qcommon.h"
//=============================================================================
// Used to determine CD Path
static char cdPath[MAX_OSPATH];
// Used to determine local installation path
static char installPath[MAX_OSPATH];
// Used to determine where to store user-specific files
static char homePath[MAX_OSPATH];
/*
================
Sys_Milliseconds
================
*/
/* base time in seconds, that's our origin
timeval:tv_sec is an int:
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;
/* current time in ms, using sys_timeBase as origin
NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
0x7fffffff ms - ~24 days
although timeval:tv_usec is an int, I'm not sure wether it is actually used as an unsigned int
(which would affect the wrap period) */
int curtime;
int Sys_Milliseconds( void ) {
struct timeval tp;
gettimeofday( &tp, NULL );
if ( !sys_timeBase ) {
sys_timeBase = tp.tv_sec;
return tp.tv_usec / 1000;
}
curtime = ( tp.tv_sec - sys_timeBase ) * 1000 + tp.tv_usec / 1000;
return curtime;
}
#if !defined( DEDICATED )
/*
================
Sys_XTimeToSysTime
sub-frame timing of events returned by X
X uses the Time typedef - unsigned long
disable with in_subframe 0
sys_timeBase*1000 is the number of ms since the Epoch of our origin
xtime is in ms and uses the Epoch as origin
Time data type is an unsigned long: 0xffffffff ms - ~49 days period
I didn't find much info in the XWindow documentation about the wrapping
we clamp sys_timeBase*1000 to unsigned long, that gives us the current origin for xtime
the computation will still work if xtime wraps (at ~49 days period since the Epoch) after we set sys_timeBase
================
*/
extern cvar_t *in_subframe;
int Sys_XTimeToSysTime( unsigned long xtime ) {
int ret, time, test;
if ( !in_subframe->value ) {
// if you don't want to do any event times corrections
return Sys_Milliseconds();
}
// test the wrap issue
#if 0
// reference values for test: sys_timeBase 0x3dc7b5e9 xtime 0x541ea451 (read these from a test run)
// xtime will wrap in 0xabe15bae ms >~ 0x2c0056 s (33 days from Nov 5 2002 -> 8 Dec)
// NOTE: date -d '1970-01-01 UTC 1039384002 seconds' +%c
// use sys_timeBase 0x3dc7b5e9+0x2c0056 = 0x3df3b63f
// after around 5s, xtime would have wrapped around
// we get 7132, the formula handles the wrap safely
unsigned long xtime_aux,base_aux;
int test;
// Com_Printf("sys_timeBase: %p\n", sys_timeBase);
// Com_Printf("xtime: %p\n", xtime);
xtime_aux = 500; // 500 ms after wrap
base_aux = 0x3df3b63f; // the base a few seconds before wrap
test = xtime_aux - ( unsigned long )( base_aux * 1000 );
Com_Printf( "xtime wrap test: %d\n", test );
#endif
// show_bug.cgi?id=565
// some X servers (like suse 8.1's) report weird event times
// if the game is loading, resolving DNS, etc. we are also getting old events
// so we only deal with subframe corrections that look 'normal'
ret = xtime - ( unsigned long )( sys_timeBase * 1000 );
time = Sys_Milliseconds();
test = time - ret;
//printf("delta: %d\n", test);
if ( test < 0 || test > 30 ) { // in normal conditions I've never seen this go above
return time;
}
return ret;
}
#endif
//#if 0 // bk001215 - see snapvector.nasm for replacement
#if ( defined __APPLE__ ) // rcg010206 - using this for PPC builds...
long fastftol( float f ) { // bk001213 - from win32/win_shared.c
//static int tmp;
// __asm fld f
//__asm fistp tmp
//__asm mov eax, tmp
return (long)f;
}
void Sys_SnapVector( float *v ) { // bk001213 - see win32/win_shared.c
// bk001213 - old linux
v[0] = rint( v[0] );
v[1] = rint( v[1] );
v[2] = rint( v[2] );
}
#endif
void Sys_Mkdir( const char *path ) {
mkdir( path, 0777 );
}
char *strlwr( char *s ) {
if ( s == NULL ) { // bk001204 - paranoia
assert( 0 );
return s;
}
while ( *s ) {
*s = tolower( *s );
s++;
}
return s; // bk001204 - duh
}
//============================================
#define MAX_FOUND_FILES 0x1000
// bk001129 - new in 1.26
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) {
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
DIR *fdir;
struct dirent *d;
struct stat st;
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
return;
}
if ( strlen( subdirs ) ) {
Com_sprintf( search, sizeof( search ), "%s/%s", basedir, subdirs );
} else {
Com_sprintf( search, sizeof( search ), "%s", basedir );
}
if ( ( fdir = opendir( search ) ) == NULL ) {
return;
}
while ( ( d = readdir( fdir ) ) != NULL ) {
Com_sprintf( filename, sizeof( filename ), "%s/%s", search, d->d_name );
if ( stat( filename, &st ) == -1 ) {
continue;
}
if ( st.st_mode & S_IFDIR ) {
if ( Q_stricmp( d->d_name, "." ) && Q_stricmp( d->d_name, ".." ) ) {
if ( strlen( subdirs ) ) {
Com_sprintf( newsubdirs, sizeof( newsubdirs ), "%s/%s", subdirs, d->d_name );
} else {
Com_sprintf( newsubdirs, sizeof( newsubdirs ), "%s", d->d_name );
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
}
}
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
break;
}
Com_sprintf( filename, sizeof( filename ), "%s/%s", subdirs, d->d_name );
if ( !Com_FilterPath( filter, filename, qfalse ) ) {
continue;
}
list[ *numfiles ] = CopyString( filename );
( *numfiles )++;
}
closedir( fdir );
}
// bk001129 - in 1.17 this used to be
// char **Sys_ListFiles( const char *directory, const char *extension, int *numfiles, qboolean wantsubs )
char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) {
struct dirent *d;
// char *p; // bk001204 - unused
DIR *fdir;
qboolean dironly = wantsubs;
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
//int flag; // bk001204 - unused
int i;
struct stat st;
int extLen;
if ( filter ) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
list[ nfiles ] = 0;
*numfiles = nfiles;
if ( !nfiles ) {
return NULL;
}
listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
if ( !extension ) {
extension = "";
}
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
dironly = qtrue;
}
extLen = strlen( extension );
// search
nfiles = 0;
if ( ( fdir = opendir( directory ) ) == NULL ) {
*numfiles = 0;
return NULL;
}
while ( ( d = readdir( fdir ) ) != NULL ) {
Com_sprintf( search, sizeof( search ), "%s/%s", directory, d->d_name );
if ( stat( search, &st ) == -1 ) {
continue;
}
if ( ( dironly && !( st.st_mode & S_IFDIR ) ) ||
( !dironly && ( st.st_mode & S_IFDIR ) ) ) {
continue;
}
if ( *extension ) {
if ( strlen( d->d_name ) < strlen( extension ) ||
Q_stricmp(
d->d_name + strlen( d->d_name ) - strlen( extension ),
extension ) ) {
continue; // didn't match
}
}
if ( nfiles == MAX_FOUND_FILES - 1 ) {
break;
}
list[ nfiles ] = CopyString( d->d_name );
nfiles++;
}
list[ nfiles ] = 0;
closedir( fdir );
// return a copy of the list
*numfiles = nfiles;
if ( !nfiles ) {
return NULL;
}
listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
void Sys_FreeFileList( char **list ) {
int i;
if ( !list ) {
return;
}
for ( i = 0 ; list[i] ; i++ ) {
Z_Free( list[i] );
}
Z_Free( list );
}
char *Sys_Cwd( void ) {
static char cwd[MAX_OSPATH];
getcwd( cwd, sizeof( cwd ) - 1 );
cwd[MAX_OSPATH - 1] = 0;
return cwd;
}
void Sys_SetDefaultCDPath( const char *path ) {
Q_strncpyz( cdPath, path, sizeof( cdPath ) );
}
char *Sys_DefaultCDPath( void ) {
return cdPath;
}
/*
==============
Sys_DefaultBasePath
==============
*/
char *Sys_DefaultBasePath( void ) {
if ( installPath[0] ) {
return installPath;
} else {
return Sys_Cwd();
}
}
void Sys_SetDefaultInstallPath( const char *path ) {
Q_strncpyz( installPath, path, sizeof( installPath ) );
}
char *Sys_DefaultInstallPath( void ) {
if ( *installPath ) {
return installPath;
} else {
return Sys_Cwd();
}
}
void Sys_SetDefaultHomePath( const char *path ) {
Q_strncpyz( homePath, path, sizeof( homePath ) );
}
char *Sys_DefaultHomePath( void ) {
char *p;
if ( *homePath ) {
return homePath;
}
if ( ( p = getenv( "HOME" ) ) != NULL ) {
Q_strncpyz( homePath, p, sizeof( homePath ) );
#ifdef MACOS_X
Q_strcat( homePath, sizeof( homePath ), "/Library/Application Support/WolfensteinMP" );
#else
Q_strcat( homePath, sizeof( homePath ), "/.wolf" );
#endif
if ( mkdir( homePath, 0777 ) ) {
if ( errno != EEXIST ) {
Sys_Error( "Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror( errno ), errno );
}
}
return homePath;
}
return ""; // assume current dir
}
//============================================
int Sys_GetProcessorId( void ) {
// TODO TTimo add better CPU identification?
// see Sys_GetHighQualityCPU
return CPUID_GENERIC;
}
int Sys_GetHighQualityCPU() {
// TODO TTimo see win_shared.c IsP3 || IsAthlon
return 0;
}
void Sys_ShowConsole( int visLevel, qboolean quitOnClose ) {
}
char *Sys_GetCurrentUser( void ) {
struct passwd *p;
if ( ( p = getpwuid( getuid() ) ) == NULL ) {
return "player";
}
return p->pw_name;
}
void *Sys_InitializeCriticalSection() {
return (void *)-1;
}
void Sys_EnterCriticalSection( void *ptr ) {
}
void Sys_LeaveCriticalSection( void *ptr ) {
}