From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/utils/common/cmdlib.cpp | 2014 ++++++++++++++++++++-------------------- 1 file changed, 1007 insertions(+), 1007 deletions(-) (limited to 'mp/src/utils/common/cmdlib.cpp') diff --git a/mp/src/utils/common/cmdlib.cpp b/mp/src/utils/common/cmdlib.cpp index a6962380..a5f9b747 100644 --- a/mp/src/utils/common/cmdlib.cpp +++ b/mp/src/utils/common/cmdlib.cpp @@ -1,1007 +1,1007 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -// ----------------------- -// cmdlib.c -// ----------------------- -#include "tier0/platform.h" -#ifdef IS_WINDOWS_PC -#include -#endif -#include "cmdlib.h" -#include -#include -#include "tier1/strtools.h" -#ifdef _WIN32 -#include -#endif -#include "utlvector.h" -#include "filesystem_helpers.h" -#include "utllinkedlist.h" -#include "tier0/icommandline.h" -#include "KeyValues.h" -#include "filesystem_tools.h" - -#if defined( MPI ) - - #include "vmpi.h" - #include "vmpi_tools_shared.h" - -#endif - - -#if defined( _WIN32 ) || defined( WIN32 ) -#include -#endif - -#if defined( _X360 ) -#include "xbox/xbox_win32stubs.h" -#endif - -// set these before calling CheckParm -int myargc; -char **myargv; - -char com_token[1024]; - -qboolean archive; -char archivedir[1024]; - -FileHandle_t g_pLogFile = 0; - -CUtlLinkedList g_CleanupFunctions; -CUtlLinkedList g_ExtraSpewHooks; - -bool g_bStopOnExit = false; -void (*g_ExtraSpewHook)(const char*) = NULL; - -#if defined( _WIN32 ) || defined( WIN32 ) - -void CmdLib_FPrintf( FileHandle_t hFile, const char *pFormat, ... ) -{ - static CUtlVector buf; - if ( buf.Count() == 0 ) - buf.SetCount( 1024 ); - - va_list marker; - va_start( marker, pFormat ); - - while ( 1 ) - { - int ret = Q_vsnprintf( buf.Base(), buf.Count(), pFormat, marker ); - if ( ret >= 0 ) - { - // Write the string. - g_pFileSystem->Write( buf.Base(), ret, hFile ); - - break; - } - else - { - // Make the buffer larger. - int newSize = buf.Count() * 2; - buf.SetCount( newSize ); - if ( buf.Count() != newSize ) - { - Error( "CmdLib_FPrintf: can't allocate space for text." ); - } - } - } - - va_end( marker ); -} - -char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile ) -{ - int iCur=0; - for ( ; iCur < (outSize-1); iCur++ ) - { - char c; - if ( !g_pFileSystem->Read( &c, 1, hFile ) ) - { - if ( iCur == 0 ) - return NULL; - else - break; - } - - pOut[iCur] = c; - if ( c == '\n' ) - break; - - if ( c == EOF ) - { - if ( iCur == 0 ) - return NULL; - else - break; - } - } - - pOut[iCur] = 0; - return pOut; -} - -#if !defined( _X360 ) -#include -#endif - -// This pauses before exiting if they use -StopOnExit. Useful for debugging. -class CExitStopper -{ -public: - ~CExitStopper() - { - if ( g_bStopOnExit ) - { - Warning( "\nPress any key to quit.\n" ); - getch(); - } - } -} g_ExitStopper; - - -static unsigned short g_InitialColor = 0xFFFF; -static unsigned short g_LastColor = 0xFFFF; -static unsigned short g_BadColor = 0xFFFF; -static WORD g_BackgroundFlags = 0xFFFF; -static void GetInitialColors( ) -{ -#if !defined( _X360 ) - // Get the old background attributes. - CONSOLE_SCREEN_BUFFER_INFO oldInfo; - GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo ); - g_InitialColor = g_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); - g_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY); - - g_BadColor = 0; - if (g_BackgroundFlags & BACKGROUND_RED) - g_BadColor |= FOREGROUND_RED; - if (g_BackgroundFlags & BACKGROUND_GREEN) - g_BadColor |= FOREGROUND_GREEN; - if (g_BackgroundFlags & BACKGROUND_BLUE) - g_BadColor |= FOREGROUND_BLUE; - if (g_BackgroundFlags & BACKGROUND_INTENSITY) - g_BadColor |= FOREGROUND_INTENSITY; -#endif -} - -WORD SetConsoleTextColor( int red, int green, int blue, int intensity ) -{ - WORD ret = g_LastColor; -#if !defined( _X360 ) - - g_LastColor = 0; - if( red ) g_LastColor |= FOREGROUND_RED; - if( green ) g_LastColor |= FOREGROUND_GREEN; - if( blue ) g_LastColor |= FOREGROUND_BLUE; - if( intensity ) g_LastColor |= FOREGROUND_INTENSITY; - - // Just use the initial color if there's a match... - if (g_LastColor == g_BadColor) - g_LastColor = g_InitialColor; - - SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags ); -#endif - return ret; -} - -void RestoreConsoleTextColor( WORD color ) -{ -#if !defined( _X360 ) - SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags ); - g_LastColor = color; -#endif -} - - -#if defined( CMDLIB_NODBGLIB ) - -// This can go away when everything is in bin. -void Error( char const *pMsg, ... ) -{ - va_list marker; - va_start( marker, pMsg ); - vprintf( pMsg, marker ); - va_end( marker ); - - exit( -1 ); -} - -#else - -CRITICAL_SECTION g_SpewCS; -bool g_bSpewCSInitted = false; -bool g_bSuppressPrintfOutput = false; - -SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg ) -{ - // Hopefully two threads won't call this simultaneously right at the start! - if ( !g_bSpewCSInitted ) - { - InitializeCriticalSection( &g_SpewCS ); - g_bSpewCSInitted = true; - } - - WORD old; - SpewRetval_t retVal; - - EnterCriticalSection( &g_SpewCS ); - { - if (( type == SPEW_MESSAGE ) || (type == SPEW_LOG )) - { - Color c = *GetSpewOutputColor(); - if ( c.r() != 255 || c.g() != 255 || c.b() != 255 ) - { - // custom color - old = SetConsoleTextColor( c.r(), c.g(), c.b(), c.a() ); - } - else - { - old = SetConsoleTextColor( 1, 1, 1, 0 ); - } - retVal = SPEW_CONTINUE; - } - else if( type == SPEW_WARNING ) - { - old = SetConsoleTextColor( 1, 1, 0, 1 ); - retVal = SPEW_CONTINUE; - } - else if( type == SPEW_ASSERT ) - { - old = SetConsoleTextColor( 1, 0, 0, 1 ); - retVal = SPEW_DEBUGGER; - -#ifdef MPI - // VMPI workers don't want to bring up dialogs and suchlike. - // They need to have a special function installed to handle - // the exceptions and write the minidumps. - // Install the function after VMPI_Init with a call: - // SetupToolsMinidumpHandler( VMPI_ExceptionFilter ); - if ( g_bUseMPI && !g_bMPIMaster && !Plat_IsInDebugSession() ) - { - // Generating an exception and letting the - // installed handler handle it - ::RaiseException - ( - 0, // dwExceptionCode - EXCEPTION_NONCONTINUABLE, // dwExceptionFlags - 0, // nNumberOfArguments, - NULL // const ULONG_PTR* lpArguments - ); - - // Never get here (non-continuable exception) - - VMPI_HandleCrash( pMsg, NULL, true ); - exit( 0 ); - } -#endif - } - else if( type == SPEW_ERROR ) - { - old = SetConsoleTextColor( 1, 0, 0, 1 ); - retVal = SPEW_ABORT; // doesn't matter.. we exit below so we can return an errorlevel (which dbg.dll doesn't do). - } - else - { - old = SetConsoleTextColor( 1, 1, 1, 1 ); - retVal = SPEW_CONTINUE; - } - - if ( !g_bSuppressPrintfOutput || type == SPEW_ERROR ) - printf( "%s", pMsg ); - - OutputDebugString( pMsg ); - - if ( type == SPEW_ERROR ) - { - printf( "\n" ); - OutputDebugString( "\n" ); - } - - if( g_pLogFile ) - { - CmdLib_FPrintf( g_pLogFile, "%s", pMsg ); - g_pFileSystem->Flush( g_pLogFile ); - } - - // Dispatch to other spew hooks. - FOR_EACH_LL( g_ExtraSpewHooks, i ) - g_ExtraSpewHooks[i]( pMsg ); - - RestoreConsoleTextColor( old ); - } - LeaveCriticalSection( &g_SpewCS ); - - if ( type == SPEW_ERROR ) - { - CmdLib_Exit( 1 ); - } - - return retVal; -} - - -void InstallSpewFunction() -{ - setvbuf( stdout, NULL, _IONBF, 0 ); - setvbuf( stderr, NULL, _IONBF, 0 ); - - SpewOutputFunc( CmdLib_SpewOutputFunc ); - GetInitialColors(); -} - - -void InstallExtraSpewHook( SpewHookFn pFn ) -{ - g_ExtraSpewHooks.AddToTail( pFn ); -} - -#if 0 -void CmdLib_AllocError( unsigned long size ) -{ - Error( "Error trying to allocate %d bytes.\n", size ); -} - - -int CmdLib_NewHandler( size_t size ) -{ - CmdLib_AllocError( size ); - return 0; -} -#endif - -void InstallAllocationFunctions() -{ -// _set_new_mode( 1 ); // so if malloc() fails, we exit. -// _set_new_handler( CmdLib_NewHandler ); -} - -void SetSpewFunctionLogFile( char const *pFilename ) -{ - Assert( (!g_pLogFile) ); - g_pLogFile = g_pFileSystem->Open( pFilename, "a" ); - - Assert( g_pLogFile ); - if (!g_pLogFile) - Error("Can't create LogFile:\"%s\"\n", pFilename ); - - CmdLib_FPrintf( g_pLogFile, "\n\n\n" ); -} - - -void CloseSpewFunctionLogFile() -{ - if ( g_pFileSystem && g_pLogFile ) - { - g_pFileSystem->Close( g_pLogFile ); - g_pLogFile = FILESYSTEM_INVALID_HANDLE; - } -} - - -void CmdLib_AtCleanup( CleanupFn pFn ) -{ - g_CleanupFunctions.AddToTail( pFn ); -} - - -void CmdLib_Cleanup() -{ - CloseSpewFunctionLogFile(); - - CmdLib_TermFileSystem(); - - FOR_EACH_LL( g_CleanupFunctions, i ) - g_CleanupFunctions[i](); - -#if defined( MPI ) - // Unfortunately, when you call exit(), even if you have things registered with atexit(), - // threads go into a seemingly undefined state where GetExitCodeThread gives STILL_ACTIVE - // and WaitForSingleObject will stall forever on the thread. Because of this, we must cleanup - // everything that uses threads before exiting. - VMPI_Finalize(); -#endif -} - - -void CmdLib_Exit( int exitCode ) -{ - TerminateProcess( GetCurrentProcess(), 1 ); -} - - - -#endif - -#endif - - - - -/* -=================== -ExpandWildcards - -Mimic unix command line expansion -=================== -*/ -#define MAX_EX_ARGC 1024 -int ex_argc; -char *ex_argv[MAX_EX_ARGC]; -#if defined( _WIN32 ) && !defined( _X360 ) -#include "io.h" -void ExpandWildcards (int *argc, char ***argv) -{ - struct _finddata_t fileinfo; - int handle; - int i; - char filename[1024]; - char filebase[1024]; - char *path; - - ex_argc = 0; - for (i=0 ; i<*argc ; i++) - { - path = (*argv)[i]; - if ( path[0] == '-' - || ( !strstr(path, "*") && !strstr(path, "?") ) ) - { - ex_argv[ex_argc++] = path; - continue; - } - - handle = _findfirst (path, &fileinfo); - if (handle == -1) - return; - - Q_ExtractFilePath (path, filebase, sizeof( filebase )); - - do - { - sprintf (filename, "%s%s", filebase, fileinfo.name); - ex_argv[ex_argc++] = copystring (filename); - } while (_findnext( handle, &fileinfo ) != -1); - - _findclose (handle); - } - - *argc = ex_argc; - *argv = ex_argv; -} -#else -void ExpandWildcards (int *argc, char ***argv) -{ -} -#endif - - -// only printf if in verbose mode -qboolean verbose = false; -void qprintf (const char *format, ...) -{ - if (!verbose) - return; - - va_list argptr; - va_start (argptr,format); - - char str[2048]; - Q_vsnprintf( str, sizeof(str), format, argptr ); - -#if defined( CMDLIB_NODBGLIB ) - printf( "%s", str ); -#else - Msg( "%s", str ); -#endif - - va_end (argptr); -} - - -// ---------------------------------------------------------------------------------------------------- // -// Helpers. -// ---------------------------------------------------------------------------------------------------- // - -static void CmdLib_getwd( char *out, int outSize ) -{ -#if defined( _WIN32 ) || defined( WIN32 ) - _getcwd( out, outSize ); - Q_strncat( out, "\\", outSize, COPY_ALL_CHARACTERS ); -#else - getcwd(out, outSize); - strcat(out, "/"); -#endif - Q_FixSlashes( out ); -} - -char *ExpandArg (char *path) -{ - static char full[1024]; - - if (path[0] != '/' && path[0] != '\\' && path[1] != ':') - { - CmdLib_getwd (full, sizeof( full )); - Q_strncat (full, path, sizeof( full ), COPY_ALL_CHARACTERS); - } - else - Q_strncpy (full, path, sizeof( full )); - return full; -} - - -char *ExpandPath (char *path) -{ - static char full[1024]; - if (path[0] == '/' || path[0] == '\\' || path[1] == ':') - return path; - sprintf (full, "%s%s", qdir, path); - return full; -} - - - -char *copystring(const char *s) -{ - char *b; - b = (char *)malloc(strlen(s)+1); - strcpy (b, s); - return b; -} - - -void GetHourMinuteSeconds( int nInputSeconds, int &nHours, int &nMinutes, int &nSeconds ) -{ -} - - -void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen ) -{ - int nMinutes = nInputSeconds / 60; - int nSeconds = nInputSeconds - nMinutes * 60; - int nHours = nMinutes / 60; - nMinutes -= nHours * 60; - - const char *extra[2] = { "", "s" }; - - if ( nHours > 0 ) - Q_snprintf( pOut, outLen, "%d hour%s, %d minute%s, %d second%s", nHours, extra[nHours != 1], nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] ); - else if ( nMinutes > 0 ) - Q_snprintf( pOut, outLen, "%d minute%s, %d second%s", nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] ); - else - Q_snprintf( pOut, outLen, "%d second%s", nSeconds, extra[nSeconds != 1] ); -} - - -void Q_mkdir (char *path) -{ -#if defined( _WIN32 ) || defined( WIN32 ) - if (_mkdir (path) != -1) - return; -#else - if (mkdir (path, 0777) != -1) - return; -#endif -// if (errno != EEXIST) - Error ("mkdir failed %s\n", path ); -} - -void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage ) -{ - FileSystem_Init( pFilename, maxMemoryUsage ); - if ( !g_pFileSystem ) - Error( "CmdLib_InitFileSystem failed." ); -} - -void CmdLib_TermFileSystem() -{ - FileSystem_Term(); -} - -CreateInterfaceFn CmdLib_GetFileSystemFactory() -{ - return FileSystem_GetFactory(); -} - - -/* -============ -FileTime - -returns -1 if not present -============ -*/ -int FileTime (char *path) -{ - struct stat buf; - - if (stat (path,&buf) == -1) - return -1; - - return buf.st_mtime; -} - - - -/* -============== -COM_Parse - -Parse a token out of a string -============== -*/ -char *COM_Parse (char *data) -{ - return (char*)ParseFile( data, com_token, NULL ); -} - - -/* -============================================================================= - - MISC FUNCTIONS - -============================================================================= -*/ - - -/* -================= -CheckParm - -Checks for the given parameter in the program's command line arguments -Returns the argument number (1 to argc-1) or 0 if not present -================= -*/ -int CheckParm (char *check) -{ - int i; - - for (i = 1;iSize( f ); -} - - -FileHandle_t SafeOpenWrite ( const char *filename ) -{ - FileHandle_t f = g_pFileSystem->Open(filename, "wb"); - - if (!f) - { - //Error ("Error opening %s: %s",filename,strerror(errno)); - // BUGBUG: No way to get equivalent of errno from IFileSystem! - Error ("Error opening %s! (Check for write enable)\n",filename); - } - - return f; -} - -#define MAX_CMDLIB_BASE_PATHS 10 -static char g_pBasePaths[MAX_CMDLIB_BASE_PATHS][MAX_PATH]; -static int g_NumBasePaths = 0; - -void CmdLib_AddBasePath( const char *pPath ) -{ -// printf( "CmdLib_AddBasePath( \"%s\" )\n", pPath ); - if( g_NumBasePaths < MAX_CMDLIB_BASE_PATHS ) - { - Q_strncpy( g_pBasePaths[g_NumBasePaths], pPath, MAX_PATH ); - Q_FixSlashes( g_pBasePaths[g_NumBasePaths] ); - g_NumBasePaths++; - } - else - { - Assert( 0 ); - } -} - -bool CmdLib_HasBasePath( const char *pFileName_, int &pathLength ) -{ - char *pFileName = ( char * )_alloca( strlen( pFileName_ ) + 1 ); - strcpy( pFileName, pFileName_ ); - Q_FixSlashes( pFileName ); - pathLength = 0; - int i; - for( i = 0; i < g_NumBasePaths; i++ ) - { - // see if we can rip the base off of the filename. - if( Q_strncasecmp( g_pBasePaths[i], pFileName, strlen( g_pBasePaths[i] ) ) == 0 ) - { - pathLength = strlen( g_pBasePaths[i] ); - return true; - } - } - return false; -} - -int CmdLib_GetNumBasePaths( void ) -{ - return g_NumBasePaths; -} - -const char *CmdLib_GetBasePath( int i ) -{ - Assert( i >= 0 && i < g_NumBasePaths ); - return g_pBasePaths[i]; -} - - -//----------------------------------------------------------------------------- -// Like ExpandPath but expands the path for each base path like SafeOpenRead -//----------------------------------------------------------------------------- -int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath ) -{ - int nPathLength = 0; - - pszPath = ExpandPath( const_cast< char * >( pszPath ) ); // Kind of redundant but it's how CmdLib_HasBasePath needs things - - if ( CmdLib_HasBasePath( pszPath, nPathLength ) ) - { - pszPath = pszPath + nPathLength; - for ( int i = 0; i < CmdLib_GetNumBasePaths(); ++i ) - { - CUtlString &expandedPath = expandedPathList[ expandedPathList.AddToTail( CmdLib_GetBasePath( i ) ) ]; - expandedPath += pszPath; - } - } - else - { - expandedPathList.AddToTail( pszPath ); - } - - return expandedPathList.Count(); -} - - -FileHandle_t SafeOpenRead( const char *filename ) -{ - int pathLength; - FileHandle_t f = 0; - if( CmdLib_HasBasePath( filename, pathLength ) ) - { - filename = filename + pathLength; - int i; - for( i = 0; i < g_NumBasePaths; i++ ) - { - char tmp[MAX_PATH]; - strcpy( tmp, g_pBasePaths[i] ); - strcat( tmp, filename ); - f = g_pFileSystem->Open( tmp, "rb" ); - if( f ) - { - return f; - } - } - Error ("Error opening %s\n",filename ); - return f; - } - else - { - f = g_pFileSystem->Open( filename, "rb" ); - if ( !f ) - Error ("Error opening %s",filename ); - - return f; - } -} - -void SafeRead( FileHandle_t f, void *buffer, int count) -{ - if ( g_pFileSystem->Read (buffer, count, f) != (size_t)count) - Error ("File read failure"); -} - - -void SafeWrite ( FileHandle_t f, void *buffer, int count) -{ - if (g_pFileSystem->Write (buffer, count, f) != (size_t)count) - Error ("File write failure"); -} - - -/* -============== -FileExists -============== -*/ -qboolean FileExists ( const char *filename ) -{ - FileHandle_t hFile = g_pFileSystem->Open( filename, "rb" ); - if ( hFile == FILESYSTEM_INVALID_HANDLE ) - { - return false; - } - else - { - g_pFileSystem->Close( hFile ); - return true; - } -} - -/* -============== -LoadFile -============== -*/ -int LoadFile ( const char *filename, void **bufferptr ) -{ - int length = 0; - void *buffer; - - FileHandle_t f = SafeOpenRead (filename); - if ( FILESYSTEM_INVALID_HANDLE != f ) - { - length = Q_filelength (f); - buffer = malloc (length+1); - ((char *)buffer)[length] = 0; - SafeRead (f, buffer, length); - g_pFileSystem->Close (f); - *bufferptr = buffer; - } - else - { - *bufferptr = NULL; - } - return length; -} - - - -/* -============== -SaveFile -============== -*/ -void SaveFile ( const char *filename, void *buffer, int count ) -{ - FileHandle_t f = SafeOpenWrite (filename); - SafeWrite (f, buffer, count); - g_pFileSystem->Close (f); -} - -/* -==================== -Extract file parts -==================== -*/ -// FIXME: should include the slash, otherwise -// backing to an empty path will be wrong when appending a slash - - - -/* -============== -ParseNum / ParseHex -============== -*/ -int ParseHex (char *hex) -{ - char *str; - int num; - - num = 0; - str = hex; - - while (*str) - { - num <<= 4; - if (*str >= '0' && *str <= '9') - num += *str-'0'; - else if (*str >= 'a' && *str <= 'f') - num += 10 + *str-'a'; - else if (*str >= 'A' && *str <= 'F') - num += 10 + *str-'A'; - else - Error ("Bad hex number: %s",hex); - str++; - } - - return num; -} - - -int ParseNum (char *str) -{ - if (str[0] == '$') - return ParseHex (str+1); - if (str[0] == '0' && str[1] == 'x') - return ParseHex (str+2); - return atol (str); -} - -/* -============ -CreatePath -============ -*/ -void CreatePath (char *path) -{ - char *ofs, c; - - // strip the drive - if (path[1] == ':') - path += 2; - - for (ofs = path+1 ; *ofs ; ofs++) - { - c = *ofs; - if (c == '/' || c == '\\') - { // create the directory - *ofs = 0; - Q_mkdir (path); - *ofs = c; - } - } -} - -//----------------------------------------------------------------------------- -// Creates a path, path may already exist -//----------------------------------------------------------------------------- -#if defined( _WIN32 ) || defined( WIN32 ) -void SafeCreatePath( char *path ) -{ - char *ptr; - - // skip past the drive path, but don't strip - if ( path[1] == ':' ) - { - ptr = strchr( path, '\\' ); - } - else - { - ptr = path; - } - while ( ptr ) - { - ptr = strchr( ptr+1, '\\' ); - if ( ptr ) - { - *ptr = '\0'; - _mkdir( path ); - *ptr = '\\'; - } - } -} -#endif - -/* -============ -QCopyFile - - Used to archive source files -============ -*/ -void QCopyFile (char *from, char *to) -{ - void *buffer; - int length; - - length = LoadFile (from, &buffer); - CreatePath (to); - SaveFile (to, buffer, length); - free (buffer); -} - - - +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// ----------------------- +// cmdlib.c +// ----------------------- +#include "tier0/platform.h" +#ifdef IS_WINDOWS_PC +#include +#endif +#include "cmdlib.h" +#include +#include +#include "tier1/strtools.h" +#ifdef _WIN32 +#include +#endif +#include "utlvector.h" +#include "filesystem_helpers.h" +#include "utllinkedlist.h" +#include "tier0/icommandline.h" +#include "KeyValues.h" +#include "filesystem_tools.h" + +#if defined( MPI ) + + #include "vmpi.h" + #include "vmpi_tools_shared.h" + +#endif + + +#if defined( _WIN32 ) || defined( WIN32 ) +#include +#endif + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; + +qboolean archive; +char archivedir[1024]; + +FileHandle_t g_pLogFile = 0; + +CUtlLinkedList g_CleanupFunctions; +CUtlLinkedList g_ExtraSpewHooks; + +bool g_bStopOnExit = false; +void (*g_ExtraSpewHook)(const char*) = NULL; + +#if defined( _WIN32 ) || defined( WIN32 ) + +void CmdLib_FPrintf( FileHandle_t hFile, const char *pFormat, ... ) +{ + static CUtlVector buf; + if ( buf.Count() == 0 ) + buf.SetCount( 1024 ); + + va_list marker; + va_start( marker, pFormat ); + + while ( 1 ) + { + int ret = Q_vsnprintf( buf.Base(), buf.Count(), pFormat, marker ); + if ( ret >= 0 ) + { + // Write the string. + g_pFileSystem->Write( buf.Base(), ret, hFile ); + + break; + } + else + { + // Make the buffer larger. + int newSize = buf.Count() * 2; + buf.SetCount( newSize ); + if ( buf.Count() != newSize ) + { + Error( "CmdLib_FPrintf: can't allocate space for text." ); + } + } + } + + va_end( marker ); +} + +char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile ) +{ + int iCur=0; + for ( ; iCur < (outSize-1); iCur++ ) + { + char c; + if ( !g_pFileSystem->Read( &c, 1, hFile ) ) + { + if ( iCur == 0 ) + return NULL; + else + break; + } + + pOut[iCur] = c; + if ( c == '\n' ) + break; + + if ( c == EOF ) + { + if ( iCur == 0 ) + return NULL; + else + break; + } + } + + pOut[iCur] = 0; + return pOut; +} + +#if !defined( _X360 ) +#include +#endif + +// This pauses before exiting if they use -StopOnExit. Useful for debugging. +class CExitStopper +{ +public: + ~CExitStopper() + { + if ( g_bStopOnExit ) + { + Warning( "\nPress any key to quit.\n" ); + getch(); + } + } +} g_ExitStopper; + + +static unsigned short g_InitialColor = 0xFFFF; +static unsigned short g_LastColor = 0xFFFF; +static unsigned short g_BadColor = 0xFFFF; +static WORD g_BackgroundFlags = 0xFFFF; +static void GetInitialColors( ) +{ +#if !defined( _X360 ) + // Get the old background attributes. + CONSOLE_SCREEN_BUFFER_INFO oldInfo; + GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo ); + g_InitialColor = g_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); + g_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY); + + g_BadColor = 0; + if (g_BackgroundFlags & BACKGROUND_RED) + g_BadColor |= FOREGROUND_RED; + if (g_BackgroundFlags & BACKGROUND_GREEN) + g_BadColor |= FOREGROUND_GREEN; + if (g_BackgroundFlags & BACKGROUND_BLUE) + g_BadColor |= FOREGROUND_BLUE; + if (g_BackgroundFlags & BACKGROUND_INTENSITY) + g_BadColor |= FOREGROUND_INTENSITY; +#endif +} + +WORD SetConsoleTextColor( int red, int green, int blue, int intensity ) +{ + WORD ret = g_LastColor; +#if !defined( _X360 ) + + g_LastColor = 0; + if( red ) g_LastColor |= FOREGROUND_RED; + if( green ) g_LastColor |= FOREGROUND_GREEN; + if( blue ) g_LastColor |= FOREGROUND_BLUE; + if( intensity ) g_LastColor |= FOREGROUND_INTENSITY; + + // Just use the initial color if there's a match... + if (g_LastColor == g_BadColor) + g_LastColor = g_InitialColor; + + SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags ); +#endif + return ret; +} + +void RestoreConsoleTextColor( WORD color ) +{ +#if !defined( _X360 ) + SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags ); + g_LastColor = color; +#endif +} + + +#if defined( CMDLIB_NODBGLIB ) + +// This can go away when everything is in bin. +void Error( char const *pMsg, ... ) +{ + va_list marker; + va_start( marker, pMsg ); + vprintf( pMsg, marker ); + va_end( marker ); + + exit( -1 ); +} + +#else + +CRITICAL_SECTION g_SpewCS; +bool g_bSpewCSInitted = false; +bool g_bSuppressPrintfOutput = false; + +SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg ) +{ + // Hopefully two threads won't call this simultaneously right at the start! + if ( !g_bSpewCSInitted ) + { + InitializeCriticalSection( &g_SpewCS ); + g_bSpewCSInitted = true; + } + + WORD old; + SpewRetval_t retVal; + + EnterCriticalSection( &g_SpewCS ); + { + if (( type == SPEW_MESSAGE ) || (type == SPEW_LOG )) + { + Color c = *GetSpewOutputColor(); + if ( c.r() != 255 || c.g() != 255 || c.b() != 255 ) + { + // custom color + old = SetConsoleTextColor( c.r(), c.g(), c.b(), c.a() ); + } + else + { + old = SetConsoleTextColor( 1, 1, 1, 0 ); + } + retVal = SPEW_CONTINUE; + } + else if( type == SPEW_WARNING ) + { + old = SetConsoleTextColor( 1, 1, 0, 1 ); + retVal = SPEW_CONTINUE; + } + else if( type == SPEW_ASSERT ) + { + old = SetConsoleTextColor( 1, 0, 0, 1 ); + retVal = SPEW_DEBUGGER; + +#ifdef MPI + // VMPI workers don't want to bring up dialogs and suchlike. + // They need to have a special function installed to handle + // the exceptions and write the minidumps. + // Install the function after VMPI_Init with a call: + // SetupToolsMinidumpHandler( VMPI_ExceptionFilter ); + if ( g_bUseMPI && !g_bMPIMaster && !Plat_IsInDebugSession() ) + { + // Generating an exception and letting the + // installed handler handle it + ::RaiseException + ( + 0, // dwExceptionCode + EXCEPTION_NONCONTINUABLE, // dwExceptionFlags + 0, // nNumberOfArguments, + NULL // const ULONG_PTR* lpArguments + ); + + // Never get here (non-continuable exception) + + VMPI_HandleCrash( pMsg, NULL, true ); + exit( 0 ); + } +#endif + } + else if( type == SPEW_ERROR ) + { + old = SetConsoleTextColor( 1, 0, 0, 1 ); + retVal = SPEW_ABORT; // doesn't matter.. we exit below so we can return an errorlevel (which dbg.dll doesn't do). + } + else + { + old = SetConsoleTextColor( 1, 1, 1, 1 ); + retVal = SPEW_CONTINUE; + } + + if ( !g_bSuppressPrintfOutput || type == SPEW_ERROR ) + printf( "%s", pMsg ); + + OutputDebugString( pMsg ); + + if ( type == SPEW_ERROR ) + { + printf( "\n" ); + OutputDebugString( "\n" ); + } + + if( g_pLogFile ) + { + CmdLib_FPrintf( g_pLogFile, "%s", pMsg ); + g_pFileSystem->Flush( g_pLogFile ); + } + + // Dispatch to other spew hooks. + FOR_EACH_LL( g_ExtraSpewHooks, i ) + g_ExtraSpewHooks[i]( pMsg ); + + RestoreConsoleTextColor( old ); + } + LeaveCriticalSection( &g_SpewCS ); + + if ( type == SPEW_ERROR ) + { + CmdLib_Exit( 1 ); + } + + return retVal; +} + + +void InstallSpewFunction() +{ + setvbuf( stdout, NULL, _IONBF, 0 ); + setvbuf( stderr, NULL, _IONBF, 0 ); + + SpewOutputFunc( CmdLib_SpewOutputFunc ); + GetInitialColors(); +} + + +void InstallExtraSpewHook( SpewHookFn pFn ) +{ + g_ExtraSpewHooks.AddToTail( pFn ); +} + +#if 0 +void CmdLib_AllocError( unsigned long size ) +{ + Error( "Error trying to allocate %d bytes.\n", size ); +} + + +int CmdLib_NewHandler( size_t size ) +{ + CmdLib_AllocError( size ); + return 0; +} +#endif + +void InstallAllocationFunctions() +{ +// _set_new_mode( 1 ); // so if malloc() fails, we exit. +// _set_new_handler( CmdLib_NewHandler ); +} + +void SetSpewFunctionLogFile( char const *pFilename ) +{ + Assert( (!g_pLogFile) ); + g_pLogFile = g_pFileSystem->Open( pFilename, "a" ); + + Assert( g_pLogFile ); + if (!g_pLogFile) + Error("Can't create LogFile:\"%s\"\n", pFilename ); + + CmdLib_FPrintf( g_pLogFile, "\n\n\n" ); +} + + +void CloseSpewFunctionLogFile() +{ + if ( g_pFileSystem && g_pLogFile ) + { + g_pFileSystem->Close( g_pLogFile ); + g_pLogFile = FILESYSTEM_INVALID_HANDLE; + } +} + + +void CmdLib_AtCleanup( CleanupFn pFn ) +{ + g_CleanupFunctions.AddToTail( pFn ); +} + + +void CmdLib_Cleanup() +{ + CloseSpewFunctionLogFile(); + + CmdLib_TermFileSystem(); + + FOR_EACH_LL( g_CleanupFunctions, i ) + g_CleanupFunctions[i](); + +#if defined( MPI ) + // Unfortunately, when you call exit(), even if you have things registered with atexit(), + // threads go into a seemingly undefined state where GetExitCodeThread gives STILL_ACTIVE + // and WaitForSingleObject will stall forever on the thread. Because of this, we must cleanup + // everything that uses threads before exiting. + VMPI_Finalize(); +#endif +} + + +void CmdLib_Exit( int exitCode ) +{ + TerminateProcess( GetCurrentProcess(), 1 ); +} + + + +#endif + +#endif + + + + +/* +=================== +ExpandWildcards + +Mimic unix command line expansion +=================== +*/ +#define MAX_EX_ARGC 1024 +int ex_argc; +char *ex_argv[MAX_EX_ARGC]; +#if defined( _WIN32 ) && !defined( _X360 ) +#include "io.h" +void ExpandWildcards (int *argc, char ***argv) +{ + struct _finddata_t fileinfo; + int handle; + int i; + char filename[1024]; + char filebase[1024]; + char *path; + + ex_argc = 0; + for (i=0 ; i<*argc ; i++) + { + path = (*argv)[i]; + if ( path[0] == '-' + || ( !strstr(path, "*") && !strstr(path, "?") ) ) + { + ex_argv[ex_argc++] = path; + continue; + } + + handle = _findfirst (path, &fileinfo); + if (handle == -1) + return; + + Q_ExtractFilePath (path, filebase, sizeof( filebase )); + + do + { + sprintf (filename, "%s%s", filebase, fileinfo.name); + ex_argv[ex_argc++] = copystring (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + + *argc = ex_argc; + *argv = ex_argv; +} +#else +void ExpandWildcards (int *argc, char ***argv) +{ +} +#endif + + +// only printf if in verbose mode +qboolean verbose = false; +void qprintf (const char *format, ...) +{ + if (!verbose) + return; + + va_list argptr; + va_start (argptr,format); + + char str[2048]; + Q_vsnprintf( str, sizeof(str), format, argptr ); + +#if defined( CMDLIB_NODBGLIB ) + printf( "%s", str ); +#else + Msg( "%s", str ); +#endif + + va_end (argptr); +} + + +// ---------------------------------------------------------------------------------------------------- // +// Helpers. +// ---------------------------------------------------------------------------------------------------- // + +static void CmdLib_getwd( char *out, int outSize ) +{ +#if defined( _WIN32 ) || defined( WIN32 ) + _getcwd( out, outSize ); + Q_strncat( out, "\\", outSize, COPY_ALL_CHARACTERS ); +#else + getcwd(out, outSize); + strcat(out, "/"); +#endif + Q_FixSlashes( out ); +} + +char *ExpandArg (char *path) +{ + static char full[1024]; + + if (path[0] != '/' && path[0] != '\\' && path[1] != ':') + { + CmdLib_getwd (full, sizeof( full )); + Q_strncat (full, path, sizeof( full ), COPY_ALL_CHARACTERS); + } + else + Q_strncpy (full, path, sizeof( full )); + return full; +} + + +char *ExpandPath (char *path) +{ + static char full[1024]; + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') + return path; + sprintf (full, "%s%s", qdir, path); + return full; +} + + + +char *copystring(const char *s) +{ + char *b; + b = (char *)malloc(strlen(s)+1); + strcpy (b, s); + return b; +} + + +void GetHourMinuteSeconds( int nInputSeconds, int &nHours, int &nMinutes, int &nSeconds ) +{ +} + + +void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen ) +{ + int nMinutes = nInputSeconds / 60; + int nSeconds = nInputSeconds - nMinutes * 60; + int nHours = nMinutes / 60; + nMinutes -= nHours * 60; + + const char *extra[2] = { "", "s" }; + + if ( nHours > 0 ) + Q_snprintf( pOut, outLen, "%d hour%s, %d minute%s, %d second%s", nHours, extra[nHours != 1], nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] ); + else if ( nMinutes > 0 ) + Q_snprintf( pOut, outLen, "%d minute%s, %d second%s", nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] ); + else + Q_snprintf( pOut, outLen, "%d second%s", nSeconds, extra[nSeconds != 1] ); +} + + +void Q_mkdir (char *path) +{ +#if defined( _WIN32 ) || defined( WIN32 ) + if (_mkdir (path) != -1) + return; +#else + if (mkdir (path, 0777) != -1) + return; +#endif +// if (errno != EEXIST) + Error ("mkdir failed %s\n", path ); +} + +void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage ) +{ + FileSystem_Init( pFilename, maxMemoryUsage ); + if ( !g_pFileSystem ) + Error( "CmdLib_InitFileSystem failed." ); +} + +void CmdLib_TermFileSystem() +{ + FileSystem_Term(); +} + +CreateInterfaceFn CmdLib_GetFileSystemFactory() +{ + return FileSystem_GetFactory(); +} + + +/* +============ +FileTime + +returns -1 if not present +============ +*/ +int FileTime (char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + return (char*)ParseFile( data, com_token, NULL ); +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (char *check) +{ + int i; + + for (i = 1;iSize( f ); +} + + +FileHandle_t SafeOpenWrite ( const char *filename ) +{ + FileHandle_t f = g_pFileSystem->Open(filename, "wb"); + + if (!f) + { + //Error ("Error opening %s: %s",filename,strerror(errno)); + // BUGBUG: No way to get equivalent of errno from IFileSystem! + Error ("Error opening %s! (Check for write enable)\n",filename); + } + + return f; +} + +#define MAX_CMDLIB_BASE_PATHS 10 +static char g_pBasePaths[MAX_CMDLIB_BASE_PATHS][MAX_PATH]; +static int g_NumBasePaths = 0; + +void CmdLib_AddBasePath( const char *pPath ) +{ +// printf( "CmdLib_AddBasePath( \"%s\" )\n", pPath ); + if( g_NumBasePaths < MAX_CMDLIB_BASE_PATHS ) + { + Q_strncpy( g_pBasePaths[g_NumBasePaths], pPath, MAX_PATH ); + Q_FixSlashes( g_pBasePaths[g_NumBasePaths] ); + g_NumBasePaths++; + } + else + { + Assert( 0 ); + } +} + +bool CmdLib_HasBasePath( const char *pFileName_, int &pathLength ) +{ + char *pFileName = ( char * )_alloca( strlen( pFileName_ ) + 1 ); + strcpy( pFileName, pFileName_ ); + Q_FixSlashes( pFileName ); + pathLength = 0; + int i; + for( i = 0; i < g_NumBasePaths; i++ ) + { + // see if we can rip the base off of the filename. + if( Q_strncasecmp( g_pBasePaths[i], pFileName, strlen( g_pBasePaths[i] ) ) == 0 ) + { + pathLength = strlen( g_pBasePaths[i] ); + return true; + } + } + return false; +} + +int CmdLib_GetNumBasePaths( void ) +{ + return g_NumBasePaths; +} + +const char *CmdLib_GetBasePath( int i ) +{ + Assert( i >= 0 && i < g_NumBasePaths ); + return g_pBasePaths[i]; +} + + +//----------------------------------------------------------------------------- +// Like ExpandPath but expands the path for each base path like SafeOpenRead +//----------------------------------------------------------------------------- +int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath ) +{ + int nPathLength = 0; + + pszPath = ExpandPath( const_cast< char * >( pszPath ) ); // Kind of redundant but it's how CmdLib_HasBasePath needs things + + if ( CmdLib_HasBasePath( pszPath, nPathLength ) ) + { + pszPath = pszPath + nPathLength; + for ( int i = 0; i < CmdLib_GetNumBasePaths(); ++i ) + { + CUtlString &expandedPath = expandedPathList[ expandedPathList.AddToTail( CmdLib_GetBasePath( i ) ) ]; + expandedPath += pszPath; + } + } + else + { + expandedPathList.AddToTail( pszPath ); + } + + return expandedPathList.Count(); +} + + +FileHandle_t SafeOpenRead( const char *filename ) +{ + int pathLength; + FileHandle_t f = 0; + if( CmdLib_HasBasePath( filename, pathLength ) ) + { + filename = filename + pathLength; + int i; + for( i = 0; i < g_NumBasePaths; i++ ) + { + char tmp[MAX_PATH]; + strcpy( tmp, g_pBasePaths[i] ); + strcat( tmp, filename ); + f = g_pFileSystem->Open( tmp, "rb" ); + if( f ) + { + return f; + } + } + Error ("Error opening %s\n",filename ); + return f; + } + else + { + f = g_pFileSystem->Open( filename, "rb" ); + if ( !f ) + Error ("Error opening %s",filename ); + + return f; + } +} + +void SafeRead( FileHandle_t f, void *buffer, int count) +{ + if ( g_pFileSystem->Read (buffer, count, f) != (size_t)count) + Error ("File read failure"); +} + + +void SafeWrite ( FileHandle_t f, void *buffer, int count) +{ + if (g_pFileSystem->Write (buffer, count, f) != (size_t)count) + Error ("File write failure"); +} + + +/* +============== +FileExists +============== +*/ +qboolean FileExists ( const char *filename ) +{ + FileHandle_t hFile = g_pFileSystem->Open( filename, "rb" ); + if ( hFile == FILESYSTEM_INVALID_HANDLE ) + { + return false; + } + else + { + g_pFileSystem->Close( hFile ); + return true; + } +} + +/* +============== +LoadFile +============== +*/ +int LoadFile ( const char *filename, void **bufferptr ) +{ + int length = 0; + void *buffer; + + FileHandle_t f = SafeOpenRead (filename); + if ( FILESYSTEM_INVALID_HANDLE != f ) + { + length = Q_filelength (f); + buffer = malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + g_pFileSystem->Close (f); + *bufferptr = buffer; + } + else + { + *bufferptr = NULL; + } + return length; +} + + + +/* +============== +SaveFile +============== +*/ +void SaveFile ( const char *filename, void *buffer, int count ) +{ + FileHandle_t f = SafeOpenWrite (filename); + SafeWrite (f, buffer, count); + g_pFileSystem->Close (f); +} + +/* +==================== +Extract file parts +==================== +*/ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash + + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (char *hex) +{ + char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + +/* +============ +CreatePath +============ +*/ +void CreatePath (char *path) +{ + char *ofs, c; + + // strip the drive + if (path[1] == ':') + path += 2; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + *ofs = 0; + Q_mkdir (path); + *ofs = c; + } + } +} + +//----------------------------------------------------------------------------- +// Creates a path, path may already exist +//----------------------------------------------------------------------------- +#if defined( _WIN32 ) || defined( WIN32 ) +void SafeCreatePath( char *path ) +{ + char *ptr; + + // skip past the drive path, but don't strip + if ( path[1] == ':' ) + { + ptr = strchr( path, '\\' ); + } + else + { + ptr = path; + } + while ( ptr ) + { + ptr = strchr( ptr+1, '\\' ); + if ( ptr ) + { + *ptr = '\0'; + _mkdir( path ); + *ptr = '\\'; + } + } +} +#endif + +/* +============ +QCopyFile + + Used to archive source files +============ +*/ +void QCopyFile (char *from, char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} + + + -- cgit v1.2.3