/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena 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 2 of the License, or (at your option) any later version. Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "../qcommon/q_shared.h" #include "../qcommon/qcommon.h" #include "sys_local.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // Used to determine where to store user-specific files static char homePath[ MAX_OSPATH ] = { 0 }; #ifndef DEDICATED static UINT timerResolution = 0; #endif #ifdef __WIN64__ void Sys_SnapVector( float *v ) { v[0] = rint(v[0]); v[1] = rint(v[1]); v[2] = rint(v[2]); } #endif /* ================ Sys_DefaultHomePath ================ */ char *Sys_DefaultHomePath( void ) { TCHAR szPath[MAX_PATH]; FARPROC qSHGetFolderPath; HMODULE shfolder = LoadLibrary("shfolder.dll"); if( !*homePath ) { if(shfolder == NULL) { Com_Printf("Unable to load SHFolder.dll\n"); return NULL; } qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA"); if(qSHGetFolderPath == NULL) { Com_Printf("Unable to find SHGetFolderPath in SHFolder.dll\n"); FreeLibrary(shfolder); return NULL; } if( !SUCCEEDED( qSHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, szPath ) ) ) { Com_Printf("Unable to detect CSIDL_APPDATA\n"); FreeLibrary(shfolder); return NULL; } Q_strncpyz( homePath, szPath, sizeof( homePath ) ); Q_strcat( homePath, sizeof( homePath ), "\\Quake3" ); FreeLibrary(shfolder); } return homePath; } /* ================ Sys_TempPath ================ */ const char *Sys_TempPath( void ) { static TCHAR path[ MAX_PATH ]; DWORD length; length = GetTempPath( sizeof( path ), path ); if( length > sizeof( path ) || length == 0 ) return Sys_DefaultHomePath( ); else return path; } /* ================ Sys_Milliseconds ================ */ int sys_timeBase; int Sys_Milliseconds (void) { int sys_curtime; static qboolean initialized = qfalse; if (!initialized) { sys_timeBase = timeGetTime(); initialized = qtrue; } sys_curtime = timeGetTime() - sys_timeBase; return sys_curtime; } #ifndef __GNUC__ //see snapvectora.s /* ================ Sys_SnapVector ================ */ void Sys_SnapVector( float *v ) { 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; } #endif /* ================ Sys_RandomBytes ================ */ qboolean Sys_RandomBytes( byte *string, int len ) { HCRYPTPROV prov; if( !CryptAcquireContext( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) { return qfalse; } if( !CryptGenRandom( prov, len, (BYTE *)string ) ) { CryptReleaseContext( prov, 0 ); return qfalse; } CryptReleaseContext( prov, 0 ); return qtrue; } /* ================ Sys_GetCurrentUser ================ */ char *Sys_GetCurrentUser( void ) { static char s_userName[1024]; unsigned long size = sizeof( s_userName ); if( !GetUserName( s_userName, &size ) ) strcpy( s_userName, "player" ); if( !s_userName[0] ) { strcpy( s_userName, "player" ); } 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 /* ================== Sys_LowPhysicalMemory ================== */ qboolean Sys_LowPhysicalMemory( void ) { MEMORYSTATUS stat; GlobalMemoryStatus (&stat); return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse; } /* ============== Sys_Basename ============== */ const char *Sys_Basename( char *path ) { static char base[ MAX_OSPATH ] = { 0 }; int length; length = strlen( path ) - 1; // Skip trailing slashes while( length > 0 && path[ length ] == '\\' ) length--; while( length > 0 && path[ length - 1 ] != '\\' ) length--; Q_strncpyz( base, &path[ length ], sizeof( base ) ); length = strlen( base ) - 1; // Strip trailing slashes while( length > 0 && base[ length ] == '\\' ) base[ length-- ] = '\0'; return base; } /* ============== Sys_Dirname ============== */ const char *Sys_Dirname( char *path ) { static char dir[ MAX_OSPATH ] = { 0 }; int length; Q_strncpyz( dir, path, sizeof( dir ) ); length = strlen( dir ) - 1; while( length > 0 && dir[ length ] != '\\' ) length--; dir[ length ] = '\0'; return dir; } /* ============== Sys_Mkdir ============== */ qboolean Sys_Mkdir( const char *path ) { if( !CreateDirectory( path, NULL ) ) { if( GetLastError( ) != ERROR_ALREADY_EXISTS ) return qfalse; } return qtrue; } /* ============== Sys_Cwd ============== */ char *Sys_Cwd( void ) { static char cwd[MAX_OSPATH]; _getcwd( cwd, sizeof( cwd ) - 1 ); cwd[MAX_OSPATH-1] = 0; return cwd; } /* ============================================================== DIRECTORY SCANNING ============================================================== */ #define MAX_FOUND_FILES 0x1000 /* ============== Sys_ListFilteredFiles ============== */ 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]; intptr_t findhandle; struct _finddata_t findinfo; 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 ); } findhandle = _findfirst (search, &findinfo); if (findhandle == -1) { return; } do { if (findinfo.attrib & _A_SUBDIR) { if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) { if (strlen(subdirs)) { Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name); } else { Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name); } Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles ); } } if ( *numfiles >= MAX_FOUND_FILES - 1 ) { break; } Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name ); if (!Com_FilterPath( filter, filename, qfalse )) continue; list[ *numfiles ] = CopyString( filename ); (*numfiles)++; } while ( _findnext (findhandle, &findinfo) != -1 ); _findclose (findhandle); } /* ============== strgtr ============== */ static qboolean strgtr(const char *s0, const char *s1) { int l0, l1, i; l0 = strlen(s0); l1 = strlen(s1); if (l1 s0[i]) { return qtrue; } if (s1[i] < s0[i]) { return qfalse; } } return qfalse; } /* ============== Sys_ListFiles ============== */ char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) { char search[MAX_OSPATH]; int nfiles; char **listCopy; char *list[MAX_FOUND_FILES]; struct _finddata_t findinfo; intptr_t findhandle; int flag; int i; 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 = ""; } // passing a slash as extension will find directories if ( extension[0] == '/' && extension[1] == 0 ) { extension = ""; flag = 0; } else { flag = _A_SUBDIR; } Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension ); // search nfiles = 0; findhandle = _findfirst (search, &findinfo); if (findhandle == -1) { *numfiles = 0; return NULL; } do { if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) { if ( nfiles == MAX_FOUND_FILES - 1 ) { break; } list[ nfiles ] = CopyString( findinfo.name ); nfiles++; } } while ( _findnext (findhandle, &findinfo) != -1 ); list[ nfiles ] = 0; _findclose (findhandle); // 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; do { flag = 0; for(i=1; i 0 ) { Com_Memcpy( p, buffer, size ); p += size; } *p = '\0'; if( OpenClipboard( NULL ) && EmptyClipboard( ) ) SetClipboardData( CF_TEXT, memoryHandle ); GlobalUnlock( clipMemory ); CloseClipboard( ); } } } /* ============== Sys_Dialog Display a win32 dialog box ============== */ dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title ) { UINT uType; switch( type ) { default: case DT_INFO: uType = MB_ICONINFORMATION|MB_OK; break; case DT_WARNING: uType = MB_ICONWARNING|MB_OK; break; case DT_ERROR: uType = MB_ICONERROR|MB_OK; break; case DT_YES_NO: uType = MB_ICONQUESTION|MB_YESNO; break; case DT_OK_CANCEL: uType = MB_ICONWARNING|MB_OKCANCEL; break; } switch( MessageBox( NULL, message, title, uType ) ) { default: case IDOK: return DR_OK; case IDCANCEL: return DR_CANCEL; case IDYES: return DR_YES; case IDNO: return DR_NO; } } #ifndef DEDICATED static qboolean SDL_VIDEODRIVER_externallySet = qfalse; #endif /* ============== Sys_GLimpSafeInit Windows specific "safe" GL implementation initialisation ============== */ void Sys_GLimpSafeInit( void ) { #ifndef DEDICATED if( !SDL_VIDEODRIVER_externallySet ) { // Here, we want to let SDL decide what do to unless // explicitly requested otherwise _putenv( "SDL_VIDEODRIVER=" ); } #endif } /* ============== Sys_GLimpInit Windows specific GL implementation initialisation ============== */ void Sys_GLimpInit( void ) { #ifndef DEDICATED if( !SDL_VIDEODRIVER_externallySet ) { // It's a little bit weird having in_mouse control the // video driver, but from ioq3's point of view they're // virtually the same except for the mouse input anyway if( Cvar_VariableIntegerValue( "in_mouse" ) == -1 ) { // Use the windib SDL backend, which is closest to // the behaviour of idq3 with in_mouse set to -1 _putenv( "SDL_VIDEODRIVER=windib" ); } else { // Use the DirectX SDL backend _putenv( "SDL_VIDEODRIVER=directx" ); } } #endif } /* ============== Sys_PlatformInit Windows specific initialisation ============== */ void Sys_PlatformInit( void ) { #ifndef DEDICATED TIMECAPS ptc; UINT res; const char *SDL_VIDEODRIVER = getenv( "SDL_VIDEODRIVER" ); if( SDL_VIDEODRIVER ) { Com_Printf( "SDL_VIDEODRIVER is externally set to \"%s\", " "in_mouse -1 will have no effect\n", SDL_VIDEODRIVER ); SDL_VIDEODRIVER_externallySet = qtrue; } else SDL_VIDEODRIVER_externallySet = qfalse; 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) { _putenv(va("%s=%s", name, value)); } /* ============== 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; }