You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
782 lines
18 KiB
782 lines
18 KiB
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//===========================================================================//
|
|
|
|
#include "pch_tier0.h"
|
|
#include <time.h>
|
|
|
|
#if defined(_WIN32) && !defined(_X360)
|
|
#define WINDOWS_LEAN_AND_MEAN
|
|
#define _WIN32_WINNT 0x0403
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#include <io.h>
|
|
#endif
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include "tier0/platform.h"
|
|
#if defined( _X360 )
|
|
#include "xbox/xbox_console.h"
|
|
#endif
|
|
#include "tier0/threadtools.h"
|
|
#include "tier0/minidump.h"
|
|
|
|
#include "tier0/memalloc.h"
|
|
|
|
#if defined( _PS3 )
|
|
#include <cell/fios/fios_common.h>
|
|
#include <cell/fios/fios_memory.h>
|
|
#include <cell/fios/fios_configuration.h>
|
|
#include <sys/process.h>
|
|
#include <sysutil/sysutil_common.h>
|
|
#include <sysutil/sysutil_sysparam.h>
|
|
#include <sys/time.h>
|
|
#include "tls_ps3.h"
|
|
|
|
#if !defined(_CERT)
|
|
#include "sn/LibSN.h"
|
|
#endif
|
|
|
|
/*
|
|
#include <sys/types.h>
|
|
#include <sys/process.h>
|
|
#include <sys/prx.h>
|
|
|
|
#include <sysutil/sysutil_syscache.h>
|
|
|
|
#include <cell/sysmodule.h>
|
|
*/
|
|
#include <cell/fios/fios_time.h>
|
|
#endif // _PS3
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
// Benchmark mode uses this heavy-handed method
|
|
static bool g_bBenchmarkMode = false;
|
|
#ifdef _WIN32
|
|
static double g_FakeBenchmarkTime = 0;
|
|
static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
|
|
#endif
|
|
|
|
static CThreadFastMutex g_LocalTimeMutex;
|
|
|
|
//our global error callback function. Note that this is not initialized, but static space guarantees this is NULL at app start.
|
|
//If you initialize, it will set to zero again when the CPP runs its static initializers, which could stomp the value if another
|
|
//CPP sets this value while initializing its static space
|
|
static ExitProcessWithErrorCBFn g_pfnExitProcessWithErrorCB; //= NULL
|
|
|
|
bool Plat_IsInBenchmarkMode()
|
|
{
|
|
return g_bBenchmarkMode;
|
|
}
|
|
|
|
void Plat_SetBenchmarkMode( bool bBenchmark )
|
|
{
|
|
g_bBenchmarkMode = bBenchmark;
|
|
}
|
|
|
|
#if defined( PLATFORM_WINDOWS )
|
|
|
|
static LARGE_INTEGER g_PerformanceFrequency;
|
|
static double g_PerformanceCounterToS;
|
|
static double g_PerformanceCounterToMS;
|
|
static double g_PerformanceCounterToUS;
|
|
static LARGE_INTEGER g_ClockStart;
|
|
static bool s_bTimeInitted;
|
|
|
|
static void InitTime()
|
|
{
|
|
if( !s_bTimeInitted )
|
|
{
|
|
s_bTimeInitted = true;
|
|
QueryPerformanceFrequency(&g_PerformanceFrequency);
|
|
g_PerformanceCounterToS = 1.0 / g_PerformanceFrequency.QuadPart;
|
|
g_PerformanceCounterToMS = 1e3 / g_PerformanceFrequency.QuadPart;
|
|
g_PerformanceCounterToUS = 1e6 / g_PerformanceFrequency.QuadPart;
|
|
QueryPerformanceCounter(&g_ClockStart);
|
|
}
|
|
}
|
|
|
|
double Plat_FloatTime()
|
|
{
|
|
if (! s_bTimeInitted )
|
|
InitTime();
|
|
if ( g_bBenchmarkMode )
|
|
{
|
|
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
|
|
return g_FakeBenchmarkTime;
|
|
}
|
|
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
QueryPerformanceCounter( &CurrentTime );
|
|
|
|
double fRawSeconds = (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToS;
|
|
|
|
return fRawSeconds;
|
|
}
|
|
|
|
uint32 Plat_MSTime()
|
|
{
|
|
if (! s_bTimeInitted )
|
|
InitTime();
|
|
if ( g_bBenchmarkMode )
|
|
{
|
|
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
|
|
return (uint32)(g_FakeBenchmarkTime * 1000.0);
|
|
}
|
|
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
QueryPerformanceCounter( &CurrentTime );
|
|
|
|
return (uint32) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToMS );
|
|
}
|
|
|
|
uint64 Plat_USTime()
|
|
{
|
|
if (! s_bTimeInitted )
|
|
InitTime();
|
|
if ( g_bBenchmarkMode )
|
|
{
|
|
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
|
|
return (uint64)(g_FakeBenchmarkTime * 1e6);
|
|
}
|
|
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
QueryPerformanceCounter( &CurrentTime );
|
|
|
|
return (uint64) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToUS );
|
|
}
|
|
|
|
uint64 Plat_GetClockStart()
|
|
{
|
|
if ( !s_bTimeInitted )
|
|
InitTime();
|
|
return g_ClockStart.QuadPart;
|
|
}
|
|
|
|
#elif defined( PLATFORM_PS3 )
|
|
|
|
cell::fios::abstime_t g_fiosLaunchTime = 0;
|
|
|
|
double Plat_FloatTime()
|
|
{
|
|
return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime ) * 1e-6;
|
|
}
|
|
|
|
uint32 Plat_MSTime()
|
|
{
|
|
return (uint32) cell::fios::FIOSAbstimeToMilliseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime );
|
|
}
|
|
|
|
uint64 Plat_USTime()
|
|
{
|
|
return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime );
|
|
}
|
|
|
|
uint64 Plat_GetClockStart()
|
|
{
|
|
return g_fiosLaunchTime;
|
|
}
|
|
|
|
#endif // PLATFORM_WINDOWS/PLATFORM_PS3
|
|
|
|
uint64 Plat_GetTime()
|
|
{
|
|
// We just provide a wrapper on this function so we can protect access to time() everywhere.
|
|
time_t ltime;
|
|
time( <ime );
|
|
return ltime;
|
|
}
|
|
|
|
void Plat_GetLocalTime( struct tm *pNow )
|
|
{
|
|
// We just provide a wrapper on this function so we can protect access to time() everywhere.
|
|
time_t ltime;
|
|
time( <ime );
|
|
|
|
Plat_ConvertToLocalTime( ltime, pNow );
|
|
}
|
|
|
|
void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow )
|
|
{
|
|
// Since localtime() returns a global, we need to protect against multiple threads stomping it.
|
|
g_LocalTimeMutex.Lock();
|
|
|
|
time_t ltime = (time_t)nTime;
|
|
tm *pTime = localtime( <ime );
|
|
if ( pTime )
|
|
*pNow = *pTime;
|
|
else
|
|
memset( pNow, 0, sizeof( *pNow ) );
|
|
|
|
g_LocalTimeMutex.Unlock();
|
|
}
|
|
|
|
void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes )
|
|
{
|
|
g_LocalTimeMutex.Lock();
|
|
|
|
char *pStr = asctime( pTime );
|
|
strncpy( pOut, pStr, nMaxBytes );
|
|
pOut[nMaxBytes-1] = 0;
|
|
|
|
g_LocalTimeMutex.Unlock();
|
|
}
|
|
|
|
/*
|
|
// timezone
|
|
int32 Plat_timezone( void )
|
|
{
|
|
#ifdef _PS3
|
|
g_LocalTimeMutex.Lock();
|
|
int timezone = 0;
|
|
if ( cellSysutilGetSystemParamInt (CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE, &timezone ) < CELL_OK ) // Not Threadsafe
|
|
timezone = 0;
|
|
g_LocalTimeMutex.Unlock();
|
|
return timezone;
|
|
#else
|
|
return timezone;
|
|
#endif
|
|
}
|
|
|
|
// daylight savings
|
|
int32 Plat_daylight( void )
|
|
{
|
|
#ifdef _PS3
|
|
g_LocalTimeMutex.Lock();
|
|
int32 daylight = 0;
|
|
if ( cellSysutilGetSystemParamInt (CELL_SYSUTIL_SYSTEMPARAM_ID_SUMMERTIME, &daylight ) < CELL_OK )
|
|
daylight = 0;
|
|
g_LocalTimeMutex.Unlock();
|
|
return daylight;
|
|
#else
|
|
return daylight;
|
|
#endif
|
|
}
|
|
*/
|
|
void Platform_gmtime( uint64 nTime, struct tm *pTime )
|
|
{
|
|
time_t tmtTime = nTime;
|
|
#ifdef _PS3
|
|
struct tm * tmp = gmtime( &tmtTime );
|
|
* pTime = * tmp;
|
|
#else
|
|
gmtime_s( pTime, &tmtTime );
|
|
#endif
|
|
}
|
|
|
|
time_t Plat_timegm( struct tm *timeptr )
|
|
{
|
|
#ifndef _GAMECONSOLE
|
|
return _mkgmtime( timeptr );
|
|
#else
|
|
int *pnCrashHereBecauseConsolesDontSupportMkGmTime = 0;
|
|
*pnCrashHereBecauseConsolesDontSupportMkGmTime = 0;
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
void Plat_GetModuleFilename( char *pOut, int nMaxBytes )
|
|
{
|
|
#ifdef PLATFORM_WINDOWS_PC
|
|
SetLastError( ERROR_SUCCESS ); // clear the error code
|
|
GetModuleFileName( NULL, pOut, nMaxBytes );
|
|
if ( GetLastError() != ERROR_SUCCESS )
|
|
Error( "Plat_GetModuleFilename: The buffer given is too small (%d bytes).", nMaxBytes );
|
|
#elif PLATFORM_X360
|
|
pOut[0] = 0x00; // return null string on Xbox 360
|
|
#else
|
|
// We shouldn't need this on POSIX.
|
|
Assert( false );
|
|
pOut[0] = 0x00; // Null the returned string in release builds
|
|
#endif
|
|
}
|
|
|
|
void Plat_ExitProcess( int nCode )
|
|
{
|
|
#if defined( _WIN32 ) && !defined( _X360 )
|
|
// We don't want global destructors in our process OR in any DLL to get executed.
|
|
// _exit() avoids calling global destructors in our module, but not in other DLLs.
|
|
const char *pchCmdLineA = Plat_GetCommandLineA();
|
|
if ( nCode || ( strstr( pchCmdLineA, "gc.exe" ) && strstr( pchCmdLineA, "gc.dll" ) && strstr( pchCmdLineA, "-gc" ) ) )
|
|
{
|
|
int *x = NULL; *x = 1; // cause a hard crash, GC is not allowed to exit voluntarily from gc.dll
|
|
}
|
|
TerminateProcess( GetCurrentProcess(), nCode );
|
|
#elif defined(_PS3)
|
|
// We do not use this path to exit on PS3 (naturally), rather we want a clear crash:
|
|
int *x = NULL; *x = 1;
|
|
#else
|
|
_exit( nCode );
|
|
#endif
|
|
}
|
|
|
|
void Plat_ExitProcessWithError( int nCode, bool bGenerateMinidump )
|
|
{
|
|
//try to delegate out if they have registered a callback
|
|
if( g_pfnExitProcessWithErrorCB )
|
|
{
|
|
if( g_pfnExitProcessWithErrorCB( nCode ) )
|
|
return;
|
|
}
|
|
|
|
//handle default behavior
|
|
if( bGenerateMinidump )
|
|
{
|
|
//don't generate mini dumps in the debugger
|
|
if( !Plat_IsInDebugSession() )
|
|
{
|
|
WriteMiniDump();
|
|
}
|
|
}
|
|
|
|
//and exit our process
|
|
Plat_ExitProcess( nCode );
|
|
}
|
|
|
|
void Plat_SetExitProcessWithErrorCB( ExitProcessWithErrorCBFn pfnCB )
|
|
{
|
|
g_pfnExitProcessWithErrorCB = pfnCB;
|
|
}
|
|
|
|
void GetCurrentDate( int *pDay, int *pMonth, int *pYear )
|
|
{
|
|
struct tm long_time;
|
|
Plat_GetLocalTime( &long_time );
|
|
|
|
*pDay = long_time.tm_mday;
|
|
*pMonth = long_time.tm_mon + 1;
|
|
*pYear = long_time.tm_year + 1900;
|
|
}
|
|
|
|
// Wraps the thread-safe versions of asctime. buf must be at least 26 bytes
|
|
char *Plat_asctime( const struct tm *tm, char *buf, size_t bufsize )
|
|
{
|
|
#ifdef _PS3
|
|
snprintf( buf, bufsize, "%s", asctime(tm) );
|
|
return buf;
|
|
#else
|
|
if ( EINVAL == asctime_s( buf, bufsize, tm ) )
|
|
return NULL;
|
|
else
|
|
return buf;
|
|
#endif
|
|
}
|
|
|
|
|
|
// Wraps the thread-safe versions of ctime. buf must be at least 26 bytes
|
|
char *Plat_ctime( const time_t *timep, char *buf, size_t bufsize )
|
|
{
|
|
#ifdef _PS3
|
|
snprintf( buf, bufsize, "%s", ctime( timep ) );
|
|
return buf;
|
|
#else
|
|
if ( EINVAL == ctime_s( buf, bufsize, timep ) )
|
|
return NULL;
|
|
else
|
|
return buf;
|
|
#endif
|
|
}
|
|
|
|
|
|
// Wraps the thread-safe versions of gmtime
|
|
struct tm *Platform_gmtime( const time_t *timep, struct tm *result )
|
|
{
|
|
#ifdef _PS3
|
|
*result = *gmtime( timep );
|
|
return result;
|
|
#else
|
|
if ( EINVAL == gmtime_s( result, timep ) )
|
|
return NULL;
|
|
else
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
|
|
// Wraps the thread-safe versions of localtime
|
|
struct tm *Plat_localtime( const time_t *timep, struct tm *result )
|
|
{
|
|
#ifdef _PS3
|
|
*result = *localtime( timep );
|
|
return result;
|
|
#else
|
|
if ( EINVAL == localtime_s( result, timep ) )
|
|
return NULL;
|
|
else
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
bool vtune( bool resume )
|
|
{
|
|
#if IS_WINDOWS_PC
|
|
static bool bInitialized = false;
|
|
static void (__cdecl *VTResume)(void) = NULL;
|
|
static void (__cdecl *VTPause) (void) = NULL;
|
|
|
|
// Grab the Pause and Resume function pointers from the VTune DLL the first time through:
|
|
if( !bInitialized )
|
|
{
|
|
bInitialized = true;
|
|
|
|
HINSTANCE pVTuneDLL = LoadLibrary( "vtuneapi.dll" );
|
|
|
|
if( pVTuneDLL )
|
|
{
|
|
VTResume = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTResume" );
|
|
VTPause = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTPause" );
|
|
}
|
|
}
|
|
|
|
// Call the appropriate function, as indicated by the argument:
|
|
if( resume && VTResume )
|
|
{
|
|
VTResume();
|
|
return true;
|
|
|
|
}
|
|
else if( !resume && VTPause )
|
|
{
|
|
VTPause();
|
|
return true;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool Plat_IsInDebugSession()
|
|
{
|
|
#if defined( _X360 )
|
|
return (XBX_IsDebuggerPresent() != 0);
|
|
#elif defined( _WIN32 )
|
|
return (IsDebuggerPresent() != 0);
|
|
#elif defined( _PS3 ) && !defined(_CERT)
|
|
return snIsDebuggerPresent();
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void Plat_DebugString( const char * psz )
|
|
{
|
|
#ifdef _CERT
|
|
return; // do nothing!
|
|
#endif
|
|
|
|
#if defined( _X360 )
|
|
XBX_OutputDebugString( psz );
|
|
#elif defined( _WIN32 )
|
|
::OutputDebugStringA( psz );
|
|
#elif defined(_PS3)
|
|
printf("%s",psz);
|
|
#else
|
|
// do nothing?
|
|
#endif
|
|
}
|
|
|
|
|
|
#if defined( PLATFORM_WINDOWS_PC )
|
|
void Plat_MessageBox( const char *pTitle, const char *pMessage )
|
|
{
|
|
MessageBox( NULL, pMessage, pTitle, MB_OK );
|
|
}
|
|
#endif
|
|
|
|
PlatOSVersion_t Plat_GetOSVersion()
|
|
{
|
|
#ifdef PLATFORM_WINDOWS_PC
|
|
OSVERSIONINFO info;
|
|
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if ( GetVersionEx( &info ) )
|
|
{
|
|
if ( info.dwMajorVersion > 24 )
|
|
info.dwMajorVersion = 24; // clamp to fit the version in single byte
|
|
return PlatOSVersion_t( ( info.dwMajorVersion*10 ) + ( info.dwMinorVersion%10 ) );
|
|
}
|
|
return PLAT_OS_VERSION_UNKNOWN;
|
|
#elif defined( PLATFORM_X360 )
|
|
return PLAT_OS_VERSION_XBOX360;
|
|
#else
|
|
return PLAT_OS_VERSION_UNKNOWN;
|
|
#endif
|
|
}
|
|
|
|
#if defined( PLATFORM_PS3 )
|
|
//copied from platform_posix.cpp
|
|
static char g_CmdLine[ 2048 ] = "";
|
|
PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine )
|
|
{
|
|
strncpy( g_CmdLine, cmdLine, sizeof(g_CmdLine) );
|
|
g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0;
|
|
}
|
|
#endif
|
|
|
|
PLATFORM_INTERFACE const tchar *Plat_GetCommandLine()
|
|
{
|
|
#if defined( _PS3 )
|
|
#pragma message("Plat_GetCommandLine() not implemented on PS3") // ****
|
|
return g_CmdLine;
|
|
#elif defined( TCHAR_IS_WCHAR )
|
|
return GetCommandLineW();
|
|
#else
|
|
return GetCommandLine();
|
|
#endif
|
|
}
|
|
|
|
PLATFORM_INTERFACE const char *Plat_GetCommandLineA()
|
|
{
|
|
#if defined( _PS3 )
|
|
#pragma message("Plat_GetCommandLineA() not implemented on PS3") // ****
|
|
return g_CmdLine;
|
|
#else
|
|
return GetCommandLineA();
|
|
#endif
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Dynamically load a function
|
|
//-----------------------------------------------------------------------------
|
|
#ifdef PLATFORM_WINDOWS
|
|
|
|
void *Plat_GetProcAddress( const char *pszModule, const char *pszName )
|
|
{
|
|
HMODULE hModule = ::LoadLibrary( pszModule );
|
|
return ( hModule ) ? ::GetProcAddress( hModule, pszName ) : NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------- //
|
|
// Memory stuff.
|
|
//
|
|
// DEPRECATED. Still here to support binary back compatability of tier0.dll
|
|
//
|
|
// -------------------------------------------------------------------------------------------------- //
|
|
#ifndef _X360
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
|
|
typedef void (*Plat_AllocErrorFn)( unsigned long size );
|
|
|
|
void Plat_DefaultAllocErrorFn( unsigned long size )
|
|
{
|
|
}
|
|
|
|
Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
|
|
#endif
|
|
|
|
#if !defined( _X360 ) && !defined( _PS3 )
|
|
|
|
|
|
CRITICAL_SECTION g_AllocCS;
|
|
class CAllocCSInit
|
|
{
|
|
public:
|
|
CAllocCSInit()
|
|
{
|
|
InitializeCriticalSection( &g_AllocCS );
|
|
}
|
|
} g_AllocCSInit;
|
|
|
|
|
|
PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
|
|
{
|
|
EnterCriticalSection( &g_AllocCS );
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
void *pRet = MemAlloc_Alloc( size );
|
|
#else
|
|
void *pRet = malloc( size );
|
|
#endif
|
|
LeaveCriticalSection( &g_AllocCS );
|
|
if ( pRet )
|
|
{
|
|
return pRet;
|
|
}
|
|
else
|
|
{
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
g_AllocError( size );
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
|
|
{
|
|
EnterCriticalSection( &g_AllocCS );
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
void *pRet = g_pMemAlloc->Realloc( ptr, size );
|
|
#else
|
|
void *pRet = realloc( ptr, size );
|
|
#endif
|
|
LeaveCriticalSection( &g_AllocCS );
|
|
if ( pRet )
|
|
{
|
|
return pRet;
|
|
}
|
|
else
|
|
{
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
g_AllocError( size );
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
PLATFORM_INTERFACE void Plat_Free( void *ptr )
|
|
{
|
|
EnterCriticalSection( &g_AllocCS );
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
g_pMemAlloc->Free( ptr );
|
|
#else
|
|
free( ptr );
|
|
#endif
|
|
LeaveCriticalSection( &g_AllocCS );
|
|
}
|
|
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
|
|
{
|
|
g_AllocError = fn;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
#endif
|
|
|
|
void Plat_getwd( char *pWorkingDirectory, size_t nBufLen )
|
|
{
|
|
#if defined( PLATFORM_X360 )
|
|
V_tier0_strncpy( pWorkingDirectory, s_pWorkingDir, nBufLen );
|
|
#elif defined( PLATFORM_WINDOWS )
|
|
_getcwd( pWorkingDirectory, ( int )nBufLen );
|
|
V_tier0_strncat( pWorkingDirectory, "\\", ( int )nBufLen );
|
|
#else // PLATFORM_X360/PLATFORM_WINDOWS
|
|
if ( getcwd( pWorkingDirectory, nBufLen ) )
|
|
{
|
|
V_tier0_strncat( pWorkingDirectory, "/", ( int )nBufLen );
|
|
}
|
|
else
|
|
{
|
|
V_tier0_strncpy( pWorkingDirectory, "./", ( int )nBufLen );
|
|
}
|
|
#endif // PLATFORM_X360/PLATFORM_WINDOWS
|
|
}
|
|
|
|
void Plat_chdir( const char *pDir )
|
|
{
|
|
#if !defined( PLATFORM_X360 )
|
|
int nErr = _chdir( pDir );
|
|
NOTE_UNUSED( nErr );
|
|
#else // PLATFORM_X360
|
|
V_tier0_strncpy( s_pWorkingDir, pDir, sizeof( s_pWorkingDir ) );
|
|
#endif // PLATFORM_X360
|
|
}
|
|
|
|
char const * Plat_GetEnv(char const *pEnvVarName)
|
|
{
|
|
return getenv(pEnvVarName);
|
|
}
|
|
|
|
bool Plat_GetExecutablePath(char *pBuff, size_t nBuff)
|
|
{
|
|
return ::GetModuleFileNameA(NULL, pBuff, (DWORD)nBuff) > 0;
|
|
}
|
|
|
|
int Plat_chmod(const char *filename, int pmode)
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
return _chmod(filename, pmode);
|
|
#else
|
|
return chmod(filename, pmode);
|
|
#endif
|
|
}
|
|
|
|
bool Plat_FileExists(const char *pFileName)
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
// VS2015 CRT _stat on Windows XP always returns -1 (lol)
|
|
// https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
|
|
DWORD dwResult = GetFileAttributes(pFileName);
|
|
return (dwResult != INVALID_FILE_ATTRIBUTES);
|
|
#else
|
|
struct _stat fileInfo;
|
|
return (_stat(pFileName, &fileInfo) != -1);
|
|
#endif
|
|
}
|
|
|
|
size_t Plat_FileSize(const char *pFileName)
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
// VS2015 CRT _stat on Windows XP always returns -1 (lol)
|
|
// https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
|
|
WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
|
|
BOOL bSuccess = GetFileAttributesEx(pFileName, GetFileExInfoStandard, &fileAttributes);
|
|
if (!bSuccess)
|
|
return 0;
|
|
|
|
uint64 ulFileSize;
|
|
ulFileSize = fileAttributes.nFileSizeHigh;
|
|
ulFileSize <<= 32;
|
|
ulFileSize |= fileAttributes.nFileSizeLow;
|
|
return (size_t)ulFileSize;
|
|
#else
|
|
struct _stat fileInfo;
|
|
if (_stat(pFileName, &fileInfo) == -1)
|
|
return 0;
|
|
|
|
return fileInfo.st_size;
|
|
#endif
|
|
}
|
|
|
|
bool Plat_IsDirectory(const char *pFilepath)
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
// VS2015 CRT _stat on Windows XP always returns -1 (lol)
|
|
// https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
|
|
DWORD dwResult = GetFileAttributes(pFilepath);
|
|
if (dwResult == INVALID_FILE_ATTRIBUTES)
|
|
return false;
|
|
|
|
return (dwResult & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
#else
|
|
struct _stat fileInfo;
|
|
if (_stat(pFilepath, &fileInfo) == -1)
|
|
return false;
|
|
|
|
return ((fileInfo.st_mode & _S_IFDIR) != 0);
|
|
#endif
|
|
}
|
|
|
|
bool Plat_FileIsReadOnly(const char *pFileName)
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
// VS2015 CRT _stat on Windows XP always returns -1 (lol)
|
|
// https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
|
|
DWORD dwResult = GetFileAttributes(pFileName);
|
|
if (dwResult == INVALID_FILE_ATTRIBUTES)
|
|
return false; // See below.
|
|
|
|
return (dwResult & FILE_ATTRIBUTE_READONLY) != 0;
|
|
#else
|
|
struct _stat fileInfo;
|
|
if (_stat(pFileName, &fileInfo) == -1)
|
|
return false; //for the purposes of this test, a nonexistent file is more writable than it is readable.
|
|
|
|
return ((fileInfo.st_mode & _S_IWRITE) == 0);
|
|
#endif
|
|
}
|