aboutsummaryrefslogtreecommitdiff
path: root/sp/src/utils/common/cmdlib.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /sp/src/utils/common/cmdlib.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'sp/src/utils/common/cmdlib.cpp')
-rw-r--r--sp/src/utils/common/cmdlib.cpp2014
1 files changed, 1007 insertions, 1007 deletions
diff --git a/sp/src/utils/common/cmdlib.cpp b/sp/src/utils/common/cmdlib.cpp
index a6962380..a5f9b747 100644
--- a/sp/src/utils/common/cmdlib.cpp
+++ b/sp/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 <windows.h>
-#endif
-#include "cmdlib.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "tier1/strtools.h"
-#ifdef _WIN32
-#include <conio.h>
-#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 <direct.h>
-#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<CleanupFn, unsigned short> g_CleanupFunctions;
-CUtlLinkedList<SpewHookFn, unsigned short> 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<char> 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 <wincon.h>
-#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;i<myargc;i++)
- {
- if ( !Q_strcasecmp(check, myargv[i]) )
- return i;
- }
-
- return 0;
-}
-
-
-
-/*
-================
-Q_filelength
-================
-*/
-int Q_filelength (FileHandle_t f)
-{
- return g_pFileSystem->Size( 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 <windows.h>
+#endif
+#include "cmdlib.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "tier1/strtools.h"
+#ifdef _WIN32
+#include <conio.h>
+#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 <direct.h>
+#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<CleanupFn, unsigned short> g_CleanupFunctions;
+CUtlLinkedList<SpewHookFn, unsigned short> 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<char> 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 <wincon.h>
+#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;i<myargc;i++)
+ {
+ if ( !Q_strcasecmp(check, myargv[i]) )
+ return i;
+ }
+
+ return 0;
+}
+
+
+
+/*
+================
+Q_filelength
+================
+*/
+int Q_filelength (FileHandle_t f)
+{
+ return g_pFileSystem->Size( 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);
+}
+
+
+