Counter Strike : Global Offensive Source Code
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.

1062 lines
21 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // -----------------------
  9. // cmdlib.c
  10. // -----------------------
  11. #include "tier0/platform.h"
  12. #ifdef IS_WINDOWS_PC
  13. #include <windows.h>
  14. #endif
  15. #include "cmdlib.h"
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include "tier1/strtools.h"
  19. #ifdef _WIN32
  20. #include <conio.h>
  21. #endif
  22. #include "utlvector.h"
  23. #include "filesystem_helpers.h"
  24. #include "utllinkedlist.h"
  25. #include "tier0/icommandline.h"
  26. #include "keyvalues.h"
  27. #include "filesystem_tools.h"
  28. #if defined( MPI )
  29. #include "vmpi.h"
  30. #include "vmpi_tools_shared.h"
  31. #endif
  32. #if defined( _WIN32 ) || defined( WIN32 )
  33. #include <direct.h>
  34. #endif
  35. #if defined( _X360 )
  36. #include "xbox/xbox_win32stubs.h"
  37. #endif
  38. // set these before calling CheckParm
  39. int myargc;
  40. char **myargv;
  41. int newdirs = 0;
  42. char com_token[ 1024 ];
  43. qboolean archive;
  44. char archivedir[ 1024 ];
  45. CUtlLinkedList<CleanupFn, unsigned short> g_CleanupFunctions;
  46. bool g_bStopOnExit = false;
  47. #if defined( _WIN32 ) || defined( WIN32 )
  48. void CmdLib_FPrintf( FileHandle_t hFile, const char *pFormat, ... )
  49. {
  50. static CUtlVector<char> buf;
  51. if ( buf.Count() == 0 )
  52. {
  53. buf.SetCount( 1024 );
  54. }
  55. va_list marker;
  56. va_start( marker, pFormat );
  57. while ( 1 )
  58. {
  59. int ret = Q_vsnprintf( buf.Base(), buf.Count(), pFormat, marker );
  60. if ( ret >= 0 )
  61. {
  62. // Write the string.
  63. g_pFileSystem->Write( buf.Base(), ret, hFile );
  64. break;
  65. }
  66. else
  67. {
  68. // Make the buffer larger.
  69. int newSize = buf.Count() * 2;
  70. buf.SetCount( newSize );
  71. if ( buf.Count() != newSize )
  72. {
  73. Error( "CmdLib_FPrintf: can't allocate space for text." );
  74. }
  75. }
  76. }
  77. va_end( marker );
  78. }
  79. char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile )
  80. {
  81. int iCur=0;
  82. for ( ; iCur < (outSize-1); iCur++ )
  83. {
  84. char c;
  85. if ( !g_pFileSystem->Read( &c, 1, hFile ) )
  86. {
  87. if ( iCur == 0 )
  88. return NULL;
  89. else
  90. break;
  91. }
  92. pOut[iCur] = c;
  93. if ( c == '\n' )
  94. break;
  95. if ( c == EOF )
  96. {
  97. if ( iCur == 0 )
  98. return NULL;
  99. else
  100. break;
  101. }
  102. }
  103. pOut[iCur] = 0;
  104. return pOut;
  105. }
  106. #if !defined( _X360 )
  107. #include <wincon.h>
  108. #endif
  109. // This pauses before exiting if they use -StopOnExit. Useful for debugging.
  110. class CExitStopper
  111. {
  112. public:
  113. ~CExitStopper()
  114. {
  115. if ( g_bStopOnExit )
  116. {
  117. Warning( "\nPress any key to quit.\n" );
  118. getch();
  119. }
  120. }
  121. } g_ExitStopper;
  122. static unsigned short g_InitialColor = 0xFFFF;
  123. static unsigned short g_LastColor = 0xFFFF;
  124. static unsigned short g_BadColor = 0xFFFF;
  125. static WORD g_BackgroundFlags = 0xFFFF;
  126. static void GetInitialColors( )
  127. {
  128. #if !defined( _X360 )
  129. // Get the old background attributes.
  130. CONSOLE_SCREEN_BUFFER_INFO oldInfo;
  131. GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo );
  132. g_InitialColor = g_LastColor = oldInfo.wAttributes & ( FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY );
  133. g_BackgroundFlags = oldInfo.wAttributes & ( BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY );
  134. g_BadColor = 0;
  135. if (g_BackgroundFlags & BACKGROUND_RED)
  136. {
  137. g_BadColor |= FOREGROUND_RED;
  138. }
  139. if (g_BackgroundFlags & BACKGROUND_GREEN)
  140. {
  141. g_BadColor |= FOREGROUND_GREEN;
  142. }
  143. if (g_BackgroundFlags & BACKGROUND_BLUE)
  144. {
  145. g_BadColor |= FOREGROUND_BLUE;
  146. }
  147. if (g_BackgroundFlags & BACKGROUND_INTENSITY)
  148. {
  149. g_BadColor |= FOREGROUND_INTENSITY;
  150. }
  151. #endif
  152. }
  153. WORD SetConsoleTextColor( int red, int green, int blue, int intensity )
  154. {
  155. WORD ret = g_LastColor;
  156. #if !defined( _X360 )
  157. g_LastColor = 0;
  158. if( red )
  159. {
  160. g_LastColor |= FOREGROUND_RED;
  161. }
  162. if( green )
  163. {
  164. g_LastColor |= FOREGROUND_GREEN;
  165. }
  166. if( blue )
  167. {
  168. g_LastColor |= FOREGROUND_BLUE;
  169. }
  170. if( intensity )
  171. {
  172. g_LastColor |= FOREGROUND_INTENSITY;
  173. }
  174. // Just use the initial color if there's a match...
  175. if (g_LastColor == g_BadColor)
  176. {
  177. g_LastColor = g_InitialColor;
  178. }
  179. SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags );
  180. #endif
  181. return ret;
  182. }
  183. void RestoreConsoleTextColor( WORD color )
  184. {
  185. #if !defined( _X360 )
  186. SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags );
  187. g_LastColor = color;
  188. #endif
  189. }
  190. #if defined( CMDLIB_NODBGLIB )
  191. // This can go away when everything is in bin.
  192. void Error( char const *pMsg, ... )
  193. {
  194. va_list marker;
  195. va_start( marker, pMsg );
  196. vprintf( pMsg, marker );
  197. va_end( marker );
  198. exit( -1 );
  199. }
  200. #else
  201. bool g_bSuppressPrintfOutput = false;
  202. void CCmdLibStandardLoggingListener::Log( const LoggingContext_t *pContext, const tchar *pMessage )
  203. {
  204. if ( ( pContext->m_Flags & LCF_DO_NOT_ECHO ) != 0 )
  205. {
  206. return;
  207. }
  208. WORD oldColor;
  209. Color spewColor = pContext->m_Color;
  210. if ( spewColor == UNSPECIFIED_LOGGING_COLOR )
  211. {
  212. switch ( pContext->m_Severity )
  213. {
  214. case LS_MESSAGE:
  215. spewColor = Color( 255, 255, 255, 0 );
  216. break;
  217. case LS_WARNING:
  218. spewColor = Color( 255, 255, 0, 255 );
  219. break;
  220. case LS_ERROR:
  221. case LS_ASSERT:
  222. spewColor = Color( 255, 0, 0, 255 );
  223. break;
  224. }
  225. }
  226. oldColor = SetConsoleTextColor( spewColor.r(), spewColor.g(), spewColor.b(), spewColor.a() );
  227. #ifdef MPI
  228. if ( pContext->m_Severity == LS_ASSERT )
  229. {
  230. // VMPI workers don't want to bring up dialogs and suchlike.
  231. // They need to have a special function installed to handle
  232. // the exceptions and write the minidumps.
  233. // Install the function after VMPI_Init with a call:
  234. // SetupToolsMinidumpHandler( VMPI_ExceptionFilter );
  235. if ( g_bUseMPI && !g_bMPIMaster && !Plat_IsInDebugSession() )
  236. {
  237. // Generating an exception and letting the
  238. // installed handler handle it
  239. ::RaiseException
  240. (
  241. 0, // dwExceptionCode
  242. EXCEPTION_NONCONTINUABLE, // dwExceptionFlags
  243. 0, // nNumberOfArguments,
  244. NULL // const ULONG_PTR* lpArguments
  245. );
  246. // Never get here (non-continuable exception)
  247. VMPI_HandleCrash( pMessage, 0, NULL, true );
  248. exit( 0 );
  249. }
  250. }
  251. #endif
  252. if ( !g_bSuppressPrintfOutput || pContext->m_Severity == LS_ERROR )
  253. {
  254. printf( "%s", pMessage );
  255. }
  256. OutputDebugString( pMessage );
  257. if ( pContext->m_Severity == LS_ERROR )
  258. {
  259. if ( !g_bSuppressPrintfOutput )
  260. {
  261. printf( "\n" );
  262. }
  263. OutputDebugString( "\n" );
  264. }
  265. RestoreConsoleTextColor( oldColor );
  266. }
  267. CCmdLibFileLoggingListener::CCmdLibFileLoggingListener() : m_pLogFile( FILESYSTEM_INVALID_HANDLE ) { }
  268. void CCmdLibFileLoggingListener::Log( const LoggingContext_t *pContext, const tchar *pMessage )
  269. {
  270. if( m_pLogFile != FILESYSTEM_INVALID_HANDLE && ( pContext->m_Flags & LCF_CONSOLE_ONLY ) == 0 )
  271. {
  272. CmdLib_FPrintf( m_pLogFile, "%s", pMessage );
  273. g_pFileSystem->Flush( m_pLogFile );
  274. }
  275. }
  276. void CCmdLibFileLoggingListener::Open( char const *pFilename )
  277. {
  278. Assert( m_pLogFile == FILESYSTEM_INVALID_HANDLE );
  279. m_pLogFile = g_pFileSystem->Open( pFilename, "a" );
  280. Assert( m_pLogFile != FILESYSTEM_INVALID_HANDLE );
  281. if ( !m_pLogFile )
  282. {
  283. Error( "Can't create LogFile:\"%s\"\n", pFilename );
  284. }
  285. CmdLib_FPrintf( m_pLogFile, "\n\n\n" );
  286. }
  287. void CCmdLibFileLoggingListener::Close()
  288. {
  289. if ( g_pFileSystem && m_pLogFile != FILESYSTEM_INVALID_HANDLE )
  290. {
  291. g_pFileSystem->Close( m_pLogFile );
  292. m_pLogFile = FILESYSTEM_INVALID_HANDLE;
  293. }
  294. }
  295. CCmdLibStandardLoggingListener g_CmdLibOutputLoggingListener;
  296. CCmdLibFileLoggingListener g_CmdLibFileLoggingListener;
  297. bool g_bInstalledSpewFunction = false;
  298. void InstallSpewFunction()
  299. {
  300. Assert( !g_bInstalledSpewFunction );
  301. if ( !g_bInstalledSpewFunction )
  302. {
  303. g_bInstalledSpewFunction = true;
  304. setvbuf( stdout, NULL, _IONBF, 0 );
  305. setvbuf( stderr, NULL, _IONBF, 0 );
  306. LoggingSystem_PushLoggingState();
  307. LoggingSystem_RegisterLoggingListener( &g_CmdLibOutputLoggingListener );
  308. LoggingSystem_RegisterLoggingListener( &g_CmdLibFileLoggingListener );
  309. GetInitialColors();
  310. }
  311. }
  312. void CmdLib_AllocError( unsigned long size )
  313. {
  314. Error( "Error trying to allocate %d bytes.\n", size );
  315. }
  316. int CmdLib_NewHandler( size_t size )
  317. {
  318. CmdLib_AllocError( size );
  319. return 0;
  320. }
  321. void InstallAllocationFunctions()
  322. {
  323. _set_new_mode( 1 ); // so if malloc() fails, we exit.
  324. _set_new_handler( CmdLib_NewHandler );
  325. }
  326. #endif
  327. void CmdLib_AtCleanup( CleanupFn pFn )
  328. {
  329. g_CleanupFunctions.AddToTail( pFn );
  330. }
  331. void CmdLib_Cleanup()
  332. {
  333. if ( g_bInstalledSpewFunction )
  334. {
  335. LoggingSystem_PopLoggingState();
  336. }
  337. g_CmdLibFileLoggingListener.Close();
  338. CmdLib_TermFileSystem();
  339. FOR_EACH_LL( g_CleanupFunctions, i )
  340. {
  341. g_CleanupFunctions[ i ]();
  342. }
  343. #if defined( MPI )
  344. // Unfortunately, when you call exit(), even if you have things registered with atexit(),
  345. // threads go into a seemingly undefined state where GetExitCodeThread gives STILL_ACTIVE
  346. // and WaitForSingleObject will stall forever on the thread. Because of this, we must cleanup
  347. // everything that uses threads before exiting.
  348. VMPI_Finalize();
  349. #endif
  350. }
  351. #endif
  352. /*
  353. ===================
  354. ExpandWildcards
  355. Mimic unix command line expansion
  356. ===================
  357. */
  358. #define MAX_EX_ARGC 1024
  359. int ex_argc;
  360. char *ex_argv[ MAX_EX_ARGC ];
  361. #if defined( _WIN32 ) && !defined( _X360 )
  362. #include "io.h"
  363. void ExpandWildcards( int *argc, char ***argv )
  364. {
  365. struct _finddata_t fileinfo;
  366. int handle;
  367. int i;
  368. char filename[ 1024 ];
  369. char filebase[ 1024 ];
  370. char *path;
  371. ex_argc = 0;
  372. for ( i = 0; i < *argc; i++ )
  373. {
  374. path = (*argv)[i];
  375. if ( path[0] == '-'
  376. || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) )
  377. {
  378. ex_argv[ ex_argc++ ] = path;
  379. continue;
  380. }
  381. handle = _findfirst( path, &fileinfo );
  382. if ( handle == -1 )
  383. return;
  384. Q_ExtractFilePath( path, filebase, sizeof( filebase ) );
  385. do
  386. {
  387. V_sprintf_safe( filename, "%s%s", filebase, fileinfo.name );
  388. ex_argv[ ex_argc++ ] = copystring( filename );
  389. } while ( _findnext( handle, &fileinfo ) != -1 );
  390. _findclose (handle);
  391. }
  392. *argc = ex_argc;
  393. *argv = ex_argv;
  394. }
  395. #else
  396. void ExpandWildcards( int *argc, char ***argv )
  397. {
  398. }
  399. #endif
  400. // only printf if in verbose mode
  401. qboolean verbose = false;
  402. void qprintf( char *format, ... )
  403. {
  404. if ( !verbose )
  405. return;
  406. va_list argptr;
  407. va_start( argptr, format );
  408. char str[ 2048 ];
  409. V_vsprintf_safe( str, format, argptr );
  410. #if defined( CMDLIB_NODBGLIB )
  411. printf( "%s", str );
  412. #else
  413. Msg( "%s", str );
  414. #endif
  415. va_end( argptr );
  416. }
  417. // ---------------------------------------------------------------------------------------------------- //
  418. // Helpers.
  419. // ---------------------------------------------------------------------------------------------------- //
  420. static void CmdLib_getwd( char *out, int outSize )
  421. {
  422. #if defined( _WIN32 ) || defined( WIN32 )
  423. _getcwd( out, outSize );
  424. Q_strncat( out, "\\", outSize, COPY_ALL_CHARACTERS );
  425. #else
  426. getwd( out );
  427. strcat( out, "/" );
  428. #endif
  429. Q_FixSlashes( out );
  430. }
  431. char *ExpandArg( char *path )
  432. {
  433. static char full[ 1024 ];
  434. if ( path[ 0 ] != '/' && path[ 0 ] != '\\' && path[ 1 ] != ':' )
  435. {
  436. CmdLib_getwd ( full, sizeof( full ) );
  437. V_strcat_safe( full, path, COPY_ALL_CHARACTERS );
  438. }
  439. else
  440. {
  441. V_strcpy_safe( full, path );
  442. }
  443. return full;
  444. }
  445. char *ExpandPath (char *path)
  446. {
  447. static char full[ 1024 ];
  448. if ( path[ 0 ] == '/' || path[ 0 ] == '\\' || path[ 1 ] == ':')
  449. return path;
  450. V_sprintf_safe( full, "%s%s", qdir, path );
  451. return full;
  452. }
  453. char *copystring(const char *s)
  454. {
  455. char *b;
  456. b = ( char * )malloc( strlen( s ) + 1 );
  457. V_strcpy( b, s );
  458. return b;
  459. }
  460. void GetHourMinuteSeconds( int nInputSeconds, int &nHours, int &nMinutes, int &nSeconds )
  461. {
  462. }
  463. void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen )
  464. {
  465. int nMinutes = nInputSeconds / 60;
  466. int nSeconds = nInputSeconds - nMinutes * 60;
  467. int nHours = nMinutes / 60;
  468. nMinutes -= nHours * 60;
  469. char *extra[ 2 ] = { "", "s" };
  470. if ( nHours > 0 )
  471. {
  472. 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 ] );
  473. }
  474. else if ( nMinutes > 0 )
  475. {
  476. Q_snprintf( pOut, outLen, "%d minute%s, %d second%s", nMinutes, extra[ nMinutes != 1 ], nSeconds, extra[ nSeconds != 1 ] );
  477. }
  478. else
  479. {
  480. Q_snprintf( pOut, outLen, "%d second%s", nSeconds, extra[ nSeconds != 1 ] );
  481. }
  482. }
  483. void Q_mkdir( char *path )
  484. {
  485. #if defined( _WIN32 ) || defined( WIN32 )
  486. if ( _mkdir( path ) != -1)
  487. return;
  488. #else
  489. if ( mkdir( path, 0777 ) != -1)
  490. return;
  491. #endif
  492. // if (errno != EEXIST)
  493. Error( "mkdir failed %s\n", path );
  494. }
  495. void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage )
  496. {
  497. FileSystem_Init( pFilename, maxMemoryUsage );
  498. if ( !g_pFileSystem )
  499. {
  500. Error( "CmdLib_InitFileSystem failed." );
  501. }
  502. }
  503. void CmdLib_TermFileSystem()
  504. {
  505. FileSystem_Term();
  506. }
  507. CreateInterfaceFn CmdLib_GetFileSystemFactory()
  508. {
  509. return FileSystem_GetFactory();
  510. }
  511. /*
  512. ============
  513. FileTime
  514. returns -1 if not present
  515. ============
  516. */
  517. int FileTime( char *path )
  518. {
  519. struct stat buf;
  520. if ( stat( path, &buf ) == -1 )
  521. return -1;
  522. return buf.st_mtime;
  523. }
  524. /*
  525. ==============
  526. COM_Parse
  527. Parse a token out of a string
  528. ==============
  529. */
  530. char *COM_Parse( char *data )
  531. {
  532. return ( char* )ParseFile( data, com_token, NULL );
  533. }
  534. /*
  535. =============================================================================
  536. MISC FUNCTIONS
  537. =============================================================================
  538. */
  539. /*
  540. =================
  541. CheckParm
  542. Checks for the given parameter in the program's command line arguments
  543. Returns the argument number (1 to argc-1) or 0 if not present
  544. =================
  545. */
  546. int CheckParm( char *check )
  547. {
  548. int i;
  549. for ( i = 1; i < myargc; i++ )
  550. {
  551. if ( !Q_strcasecmp( check, myargv[ i ] ) )
  552. return i;
  553. }
  554. return 0;
  555. }
  556. /*
  557. ================
  558. Q_filelength
  559. ================
  560. */
  561. int Q_filelength( FileHandle_t f )
  562. {
  563. return g_pFileSystem->Size( f );
  564. }
  565. FileHandle_t SafeOpenWrite( const char *filename )
  566. {
  567. FileHandle_t f = g_pFileSystem->Open( filename, "wb" );
  568. if ( !f )
  569. {
  570. //Error( "Error opening %s: %s", filename, strerror( errno ) );
  571. // BUGBUG: No way to get equivalent of errno from IFileSystem!
  572. Error( "Error opening %s! (Check for write enable)\n", filename );
  573. }
  574. return f;
  575. }
  576. #define MAX_CMDLIB_BASE_PATHS 20
  577. static char g_pBasePaths[ MAX_CMDLIB_BASE_PATHS ][ MAX_PATH ];
  578. static int g_NumBasePaths = 0;
  579. void CmdLib_AddBasePath( const char *pPath )
  580. {
  581. //printf( "CmdLib_AddBasePath( \"%s\" )\n", pPath );
  582. if( g_NumBasePaths < MAX_CMDLIB_BASE_PATHS )
  583. {
  584. V_strcpy_safe( g_pBasePaths[ g_NumBasePaths ], pPath );
  585. Q_FixSlashes( g_pBasePaths[ g_NumBasePaths ] );
  586. g_NumBasePaths++;
  587. }
  588. else
  589. {
  590. Assert( 0 );
  591. }
  592. }
  593. void CmdLib_AddNewSearchPath( const char *pPath )
  594. {
  595. static int g_nAdditionalDirectoryCount = 0;
  596. static char s_addedRelativeDirs[ MAX_CMDLIB_BASE_PATHS ][ MAX_PATH ];
  597. static int s_originalNumBasePaths = 0;
  598. static char s_originalBasePaths[ MAX_CMDLIB_BASE_PATHS ][ MAX_PATH ];
  599. if ( g_nAdditionalDirectoryCount == 0 ) // first call:
  600. {
  601. // remember all original paths
  602. s_originalNumBasePaths = g_NumBasePaths;
  603. for ( int nOriginalBasePath = 0; nOriginalBasePath < s_originalNumBasePaths; nOriginalBasePath++ )
  604. {
  605. V_strcpy_safe( s_originalBasePaths[nOriginalBasePath], g_pBasePaths[nOriginalBasePath] );
  606. }
  607. }
  608. if( g_nAdditionalDirectoryCount < MAX_CMDLIB_BASE_PATHS )
  609. {
  610. V_strcpy_safe( s_addedRelativeDirs[g_nAdditionalDirectoryCount], pPath );
  611. Q_FixSlashes( s_addedRelativeDirs[g_nAdditionalDirectoryCount] );
  612. g_nAdditionalDirectoryCount++;
  613. }
  614. else
  615. {
  616. Assert( 0 );
  617. }
  618. //update the original base paths with the new number
  619. // we'll produce a cross-product of the set of original paths and the new relative paths
  620. g_NumBasePaths = s_originalNumBasePaths + ( s_originalNumBasePaths * g_nAdditionalDirectoryCount );
  621. if ( g_NumBasePaths > MAX_CMDLIB_BASE_PATHS )
  622. {
  623. Error( "You have too many search paths, let SteveK know about this\n");
  624. }
  625. //make an array of all the new search directories and copy it back into g_pBasePaths
  626. int nGeneratedPaths = 0;
  627. for ( int nOriginalBasePath = 0; nOriginalBasePath < s_originalNumBasePaths; nOriginalBasePath++ )
  628. {
  629. for ( int nAdditionalDir = 0; nAdditionalDir < g_nAdditionalDirectoryCount; nAdditionalDir++ )
  630. {
  631. //add in the new search dirs here
  632. V_strcpy_safe( g_pBasePaths[ nGeneratedPaths ], s_originalBasePaths[ nOriginalBasePath ] );
  633. V_strcat_safe( g_pBasePaths[ nGeneratedPaths ], s_addedRelativeDirs[ nAdditionalDir ], sizeof( s_addedRelativeDirs[ nAdditionalDir ] ) );
  634. nGeneratedPaths++;
  635. }
  636. //we still need the original base path, but insert it after the newly added ones
  637. V_strcpy_safe( g_pBasePaths[ nGeneratedPaths ], s_originalBasePaths[ nOriginalBasePath ] );
  638. nGeneratedPaths++;
  639. }
  640. }
  641. bool CmdLib_HasBasePath( const char *pFileName_, int &pathLength )
  642. {
  643. char *pFileName = ( char * )stackalloc( strlen( pFileName_ ) + 1 );
  644. V_strcpy( pFileName, pFileName_ );
  645. Q_FixSlashes( pFileName );
  646. pathLength = 0;
  647. for( int i = 0; i < g_NumBasePaths; i++ )
  648. {
  649. // see if we can rip the base off of the filename.
  650. if( Q_strncasecmp( g_pBasePaths[ i ], pFileName, Q_strlen( g_pBasePaths[ i ] ) ) == 0 )
  651. {
  652. pathLength = strlen( g_pBasePaths[ i ] );
  653. return true;
  654. }
  655. }
  656. return false;
  657. }
  658. int CmdLib_GetNumBasePaths( void )
  659. {
  660. return g_NumBasePaths;
  661. }
  662. const char *CmdLib_GetBasePath( int i )
  663. {
  664. Assert( i >= 0 && i < g_NumBasePaths );
  665. return g_pBasePaths[ i ];
  666. }
  667. FileHandle_t SafeOpenRead( const char *filename )
  668. {
  669. int pathLength;
  670. FileHandle_t f = 0;
  671. if( CmdLib_HasBasePath( filename, pathLength ) )
  672. {
  673. filename = filename + pathLength;
  674. char tmp[ MAX_PATH ];
  675. for( int i = 0; i < g_NumBasePaths; i++ )
  676. {
  677. V_strcpy_safe( tmp, g_pBasePaths[ i ] );
  678. V_strcat_safe( tmp, filename );
  679. f = g_pFileSystem->Open( tmp, "rb" );
  680. if( f )
  681. {
  682. return f;
  683. }
  684. }
  685. Error( "Error opening %s\n",filename );
  686. return f;
  687. }
  688. else
  689. {
  690. f = g_pFileSystem->Open( filename, "rb" );
  691. if ( !f )
  692. {
  693. Error( "Error opening %s",filename );
  694. }
  695. return f;
  696. }
  697. }
  698. void SafeRead( FileHandle_t f, void *buffer, int count)
  699. {
  700. if ( g_pFileSystem->Read( buffer, count, f ) != ( size_t )count )
  701. {
  702. Error( "File read failure" );
  703. }
  704. }
  705. void SafeWrite ( FileHandle_t f, void *buffer, int count)
  706. {
  707. if ( g_pFileSystem->Write( buffer, count, f ) != ( size_t )count )
  708. {
  709. Error( "File write failure" );
  710. }
  711. }
  712. /*
  713. ==============
  714. FileExists
  715. ==============
  716. */
  717. qboolean FileExists( const char *filename )
  718. {
  719. FileHandle_t hFile = g_pFileSystem->Open( filename, "rb" );
  720. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  721. {
  722. return false;
  723. }
  724. else
  725. {
  726. g_pFileSystem->Close( hFile );
  727. return true;
  728. }
  729. }
  730. /*
  731. ==============
  732. LoadFile
  733. ==============
  734. */
  735. int LoadFile( const char *filename, void **bufferptr )
  736. {
  737. int length = 0;
  738. void *buffer;
  739. FileHandle_t f = SafeOpenRead( filename );
  740. if ( FILESYSTEM_INVALID_HANDLE != f )
  741. {
  742. length = Q_filelength( f );
  743. buffer = malloc( length + 1 );
  744. ( ( char * )buffer )[ length ] = 0;
  745. SafeRead( f, buffer, length );
  746. g_pFileSystem->Close( f );
  747. *bufferptr = buffer;
  748. }
  749. else
  750. {
  751. *bufferptr = NULL;
  752. }
  753. return length;
  754. }
  755. /*
  756. ==============
  757. SaveFile
  758. ==============
  759. */
  760. void SaveFile( const char *filename, void *buffer, int count )
  761. {
  762. FileHandle_t f = SafeOpenWrite( filename );
  763. SafeWrite( f, buffer, count );
  764. g_pFileSystem->Close( f );
  765. }
  766. /*
  767. ====================
  768. Extract file parts
  769. ====================
  770. */
  771. // FIXME: should include the slash, otherwise
  772. // backing to an empty path will be wrong when appending a slash
  773. /*
  774. ==============
  775. ParseNum / ParseHex
  776. ==============
  777. */
  778. int ParseHex( char *hex )
  779. {
  780. char *str;
  781. int num;
  782. num = 0;
  783. str = hex;
  784. while ( *str )
  785. {
  786. num <<= 4;
  787. if ( *str >= '0' && *str <= '9' )
  788. {
  789. num += *str - '0';
  790. }
  791. else if ( *str >= 'a' && *str <= 'f' )
  792. {
  793. num += 10 + *str - 'a';
  794. }
  795. else if ( *str >= 'A' && *str <= 'F' )
  796. {
  797. num += 10 + *str - 'A';
  798. }
  799. else
  800. {
  801. Error( "Bad hex number: %s", hex );
  802. }
  803. str++;
  804. }
  805. return num;
  806. }
  807. int ParseNum( char *str )
  808. {
  809. if ( str[ 0 ] == '$' )
  810. return ParseHex( str + 1 );
  811. if ( str[ 0 ] == '0' && str[ 1 ] == 'x' )
  812. return ParseHex( str + 2 );
  813. return atol( str );
  814. }
  815. /*
  816. ============
  817. CreatePath
  818. ============
  819. */
  820. void CreatePath( char *path )
  821. {
  822. char *ofs, c;
  823. // strip the drive
  824. if ( path[ 1 ] == ':' )
  825. path += 2;
  826. for ( ofs = path + 1; *ofs; ofs++)
  827. {
  828. c = *ofs;
  829. if ( c == '/' || c == '\\' )
  830. { // create the directory
  831. *ofs = 0;
  832. Q_mkdir( path );
  833. *ofs = c;
  834. }
  835. }
  836. }
  837. //-----------------------------------------------------------------------------
  838. // Creates a path, path may already exist
  839. //-----------------------------------------------------------------------------
  840. #if defined( _WIN32 ) || defined( WIN32 )
  841. void SafeCreatePath( char *path )
  842. {
  843. char *ptr;
  844. // skip past the drive path, but don't strip
  845. if ( path[ 1 ] == ':' )
  846. {
  847. ptr = strchr( path, '\\' );
  848. }
  849. else
  850. {
  851. ptr = path;
  852. }
  853. while ( ptr )
  854. {
  855. ptr = strchr( ptr + 1, '\\' );
  856. if ( ptr )
  857. {
  858. *ptr = '\0';
  859. _mkdir( path );
  860. *ptr = '\\';
  861. }
  862. }
  863. }
  864. #endif
  865. /*
  866. ============
  867. QCopyFile
  868. Used to archive source files
  869. ============
  870. */
  871. void QCopyFile( char *from, char *to )
  872. {
  873. void *buffer;
  874. int length;
  875. length = LoadFile( from, &buffer );
  876. CreatePath( to );
  877. SaveFile( to, buffer, length );
  878. free( buffer );
  879. }