diff options
Diffstat (limited to 'utils/depcheck/processmodule.cpp')
| -rw-r--r-- | utils/depcheck/processmodule.cpp | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/utils/depcheck/processmodule.cpp b/utils/depcheck/processmodule.cpp new file mode 100644 index 0000000..11f21b9 --- /dev/null +++ b/utils/depcheck/processmodule.cpp @@ -0,0 +1,536 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include <assert.h> +#include <time.h> +#include "stdafx.h" +#include <stdio.h> +#include <windows.h> +#include "depcheck_util.h" +#include "codeprocessor.h" + +/* +================ +UTIL_FloatTime +================ +*/ +double UTIL_FloatTime (void) +{ +// more precise, less portable + clock_t current; + static clock_t base; + static bool first = true; + + current = clock(); + + if ( first ) + { + first = false; + + base = current; + } + + return (double)(current - base)/(double)CLOCKS_PER_SEC; +} + +void CCodeProcessor::AddHeader( int depth, const char *filename, const char *rootmodule ) +{ +// if ( depth < 1 ) +// return; + if ( depth != 1 ) + return; + + // Check header list + for ( int i = 0; i < m_nHeaderCount; i++ ) + { + if ( !stricmp( m_Headers[ i ].name, filename ) ) + { + vprint( 0, "%s included twice in module %s\n", filename, rootmodule ); + return; + } + } + + // Add to list + strcpy( m_Headers[ m_nHeaderCount++ ].name, filename ); +} + +void CCodeProcessor::CreateBackup( const char *filename, bool& wasreadonly ) +{ + assert( strstr( filename, ".cpp" ) ); + + // attrib it, change extension, save it + if ( GetFileAttributes( filename ) & FILE_ATTRIBUTE_READONLY ) + { + wasreadonly = true; + + SetFileAttributes( filename, FILE_ATTRIBUTE_NORMAL ); + } + else + { + wasreadonly = false; + } + + char backupname[ 256 ]; + strcpy( backupname, filename ); + strcpy( (char *)&backupname[ strlen( filename ) - 4 ], ".bak" ); + + unlink( backupname ); + rename( filename, backupname ); + +} + +void CCodeProcessor::RestoreBackup( const char *filename, bool makereadonly ) +{ + assert( strstr( filename, ".cpp" ) ); + + char backupname[ 256 ]; + strcpy( backupname, filename ); + strcpy( (char *)&backupname[ strlen( filename ) - 4 ], ".bak" ); + + SetFileAttributes( filename, FILE_ATTRIBUTE_NORMAL ); + + unlink( filename ); + rename( backupname, filename ); + + if ( makereadonly ) + { + SetFileAttributes( filename, FILE_ATTRIBUTE_READONLY ); + } + + unlink( backupname ); +} + +bool CCodeProcessor::TryBuild( const char *rootdir, const char *filename, unsigned char *buffer, int filelength ) +{ +// vprintf( "trying build\n" ); + + FILE *fp; + fp = fopen( filename, "wb" ); + if ( !fp ) + { + assert( 0 ); + return false; + } + + fwrite( buffer, filelength, 1, fp ); + fclose( fp ); + + // if build is successful, return true + // + // return true; + char commandline[ 512 ]; + char directory[ 512 ]; + + sprintf( directory, rootdir ); + + // sprintf( commandline, "msdev engdll.dsw /MAKE \"quiver - Win32 GL Debug\" /OUT log.txt" ); + + // Builds the default configuration + sprintf( commandline, "\"C:\\Program Files\\Microsoft Visual Studio\\Common\\MSDev98\\Bin\\msdev.exe\" %s /MAKE \"%s\" /OUT log.txt", m_szDSP, m_szConfig ); + + PROCESS_INFORMATION pi; + memset( &pi, 0, sizeof( pi ) ); + + STARTUPINFO si; + memset( &si, 0, sizeof( si ) ); + si.cb = sizeof( si ); + + if ( !CreateProcess( NULL, commandline, NULL, NULL, TRUE, 0, NULL, directory, &si, &pi ) ) + { +LPVOID lpMsgBuf; +FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL +); +// Process any inserts in lpMsgBuf. +// ... +// Display the string. +MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); +// Free the buffer. +LocalFree( lpMsgBuf ); + return false; + } + + // Wait until child process exits. + WaitForSingleObject( pi.hProcess, INFINITE ); + + bool retval = false; + DWORD exitCode = -1; + if ( GetExitCodeProcess( pi.hProcess, &exitCode ) ) + { + if ( !exitCode ) + { + retval = true; + } + } + + // Close process and thread handles. + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + + return retval; +} + +void CCodeProcessor::ProcessModule( bool forcequiet, int depth, int& maxdepth, int& numheaders, int& skippedfiles, const char *baseroot, const char *root, const char *module ) +{ + char filename[ 256 ]; + + bool checkroot = false; + + if ( depth > maxdepth ) + { + maxdepth = depth; + } + + // Load the base module + sprintf( filename, "%s\\%s", root, module ); + strlwr( filename ); + + bool firstheader = true; +retry: + + // Check module list + for ( int i = 0; i < m_nModuleCount; i++ ) + { + if ( !stricmp( m_Modules[ i ].name, filename ) ) + { + if ( forcequiet ) + { + m_nHeadersProcessed++; + numheaders++; + + if ( m_Modules[ i ].skipped ) + { + skippedfiles++; + } + } + + AddHeader( depth, filename, m_szCurrentCPP ); + + return; + } + } + + int filelength; + char *buffer = (char *)COM_LoadFile( filename, &filelength ); + if ( !buffer ) + { + if ( !checkroot ) + { + checkroot = true; + // Load the base module + sprintf( filename, "%s\\%s", baseroot, module ); + goto retry; + } + m_Modules[ m_nModuleCount ].skipped = true; + strcpy( m_Modules[ m_nModuleCount++ ].name, filename ); + + skippedfiles++; + return; + } + + m_nBytesProcessed += filelength; + + m_Modules[ m_nModuleCount ].skipped = false; + strcpy( m_Modules[ m_nModuleCount++ ].name, filename ); + + bool readonly = false; + bool madechanges = false; + CreateBackup( filename, readonly ); + + if ( !forcequiet ) + { + strcpy( m_szCurrentCPP, filename ); + + vprint( 0, "- %s\n", (char *)&filename[ m_nOffset ] ); + } + + // Parse tokens looking for #include directives or class starts + char *current = buffer; + char *startofline; + + current = CC_ParseToken( current ); + while ( current ) + { + // No more tokens + if ( strlen( com_token ) <= 0 ) + break; + + if ( !stricmp( com_token, "#include" ) ) + { + startofline = current - strlen( "#include" ); + + current = CC_ParseToken( current ); + + if ( strlen( com_token ) > 0) + { + vprint( 1, "#include %s", com_token ); + m_nHeadersProcessed++; + numheaders++; + + AddHeader( depth, filename, m_szCurrentCPP ); + + bool dobuild = true; + if ( firstheader ) + { + if ( !stricmp( com_token, "cbase.h" ) ) + { + dobuild = false; + } + + if ( !TryBuild( baseroot, filename, (unsigned char *)buffer, filelength ) ) + { + // build is broken, stop + assert( 0 ); + } + } + + firstheader = false; + + if ( dobuild ) + { + // Try removing the header and compiling + char saveinfo[2]; + memcpy( saveinfo, startofline, 2 ); + startofline[ 0 ] = '/'; + startofline[ 1 ] = '/'; + + if ( TryBuild( baseroot, filename, (unsigned char *)buffer, filelength ) ) + { + vprint( 0, ", unnecessary\n" ); + madechanges = true; + } + else + { + // Restore line + memcpy( startofline, saveinfo, 2 ); + vprint( 0, "\n" ); + } + } + else + { + vprint( 0, "\n" ); + } + } + } + + current = CC_ParseToken( current ); + } + + // Save out last set of changes + { + FILE *fp; + fp = fopen( filename, "wb" ); + if ( fp ) + { + fwrite( buffer, filelength, 1, fp ); + fclose( fp ); + } + } + + COM_FreeFile( (unsigned char *)buffer ); + + if ( !madechanges ) + { + RestoreBackup( filename, readonly ); + } + + if ( !forcequiet && !GetQuiet() ) + { + vprint( 0, " %s: headers (%i)", (char *)&filename[ m_nOffset ], numheaders ); + if ( maxdepth > 1 ) + { + vprint( 0, ", depth %i", maxdepth ); + } + vprint( 0, "\n" ); + } + + m_nLinesOfCode += linesprocessed; + linesprocessed = 0; +} + +void CCodeProcessor::ProcessModules( const char *root, const char *rootmodule ) +{ + m_nFilesProcessed++; + + // Reset header list per module + m_nHeaderCount = 0; + m_nModuleCount = 0; + + int numheaders = 0; + int maxdepth = 0; + int skippedfiles = 0; + + bool canstart = false; + + if ( strstr( root, "tf2_hud" ) ) + { + canstart = true; + } + if ( !canstart ) + { + vprint( 0, "skipping %s\n", rootmodule ); + return; + } + ProcessModule( false, 0, maxdepth, numheaders, skippedfiles, root, root, rootmodule ); +} + +void CCodeProcessor::PrintResults( void ) +{ + vprint( 0, "\nChecking for errors and totaling...\n\n" ); + + vprint( 0, "parsed from %i files ( %i headers parsed )\n", + m_nFilesProcessed, + m_nHeadersProcessed ); + + vprint( 0, "%.3f K lines of code processed\n", + (double)m_nLinesOfCode / 1024.0 ); + + double elapsed = ( m_flEnd - m_flStart ); + + if ( elapsed > 0.0 ) + { + vprint( 0, "%.2f K processed in %.3f seconds, throughput %.2f KB/sec\n\n", + (double)m_nBytesProcessed / 1024.0, elapsed, (double)m_nBytesProcessed / ( 1024.0 * elapsed ) ); + } +} + +CCodeProcessor::CCodeProcessor( void ) +{ + m_nModuleCount = 0; + + m_bQuiet = false; + m_bLogToFile = false; + + m_nFilesProcessed = 0; + m_nHeadersProcessed = 0; + m_nOffset = 0; + m_nBytesProcessed = 0; + m_nLinesOfCode = 0; + m_flStart = 0.0; + m_flEnd = 0.0; + + m_szCurrentCPP[ 0 ] = 0; +} + +CCodeProcessor::~CCodeProcessor( void ) +{ +} + +char const *stristr( char const *src, char const *search ) +{ + char buf1[ 512 ]; + char buf2[ 512 ]; + + strcpy( buf1, src ); + _strlwr( buf1 ); + + strcpy( buf2, search ); + _strlwr( buf2 ); + + char *p = strstr( buf1, buf2 ); + if ( p ) + { + int len = p - buf1; + return src + len; + } + return NULL; +} + +void CCodeProcessor::ConstructModuleList_R( int level, const char *gamespecific, const char *root ) +{ + char directory[ 256 ]; + char filename[ 256 ]; + WIN32_FIND_DATA wfd; + HANDLE ff; + + sprintf( directory, "%s\\*.*", root ); + + if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE ) + return; + + do + { + if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + + if ( wfd.cFileName[ 0 ] == '.' ) + continue; + + // Once we descend down a branch, don't keep looking for hl2/tf2 in name, just recurse through all children + if ( level == 0 && !stristr( wfd.cFileName, gamespecific ) ) + continue; + + // Recurse down directory + sprintf( filename, "%s\\%s", root, wfd.cFileName ); + ConstructModuleList_R( level+1, gamespecific, filename ); + } + else + { + if ( strstr( wfd.cFileName, ".cpp" ) ) + { + ProcessModules( root, wfd.cFileName ); + } + } + } while ( FindNextFile( ff, &wfd ) ); +} + +void CCodeProcessor::Process( const char *gamespecific, const char *root, const char *dsp, const char *config ) +{ + strcpy( m_szDSP, dsp ); + strcpy( m_szConfig, config ); + + m_nBytesProcessed = 0; + m_nFilesProcessed = 0; + m_nHeadersProcessed = 0; + m_nLinesOfCode = 0; + + linesprocessed = 0; + + m_nOffset = strlen( root ) + 1; + + m_nModuleCount = 0; + m_nHeaderCount = 0; + m_flStart = UTIL_FloatTime(); + + vprint( 0, "--- Processing %s\n\n", root ); + + ConstructModuleList_R( 0, gamespecific, root ); + + m_flEnd = UTIL_FloatTime(); + + PrintResults(); +} + +void CCodeProcessor::SetQuiet( bool quiet ) +{ + m_bQuiet = quiet; +} + +bool CCodeProcessor::GetQuiet( void ) const +{ + return m_bQuiet; +} + +void CCodeProcessor::SetLogFile( bool log ) +{ + m_bLogToFile = log; +} + +bool CCodeProcessor::GetLogFile( void ) const +{ + return m_bLogToFile; +} + +static CCodeProcessor g_Processor; +ICodeProcessor *processor = ( ICodeProcessor * )&g_Processor;
\ No newline at end of file |