mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-09 10:19:38 +00:00
1
This commit is contained in:
@@ -0,0 +1,515 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "stdafx.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "mdlcheck_util.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "utldict.h"
|
||||
#include "tier1/utlstring.h"
|
||||
|
||||
bool uselogfile = false;
|
||||
bool verbose = false;
|
||||
bool checkani = false;
|
||||
|
||||
struct QCFile
|
||||
{
|
||||
char outputmodel[ MAX_PATH ];
|
||||
};
|
||||
|
||||
struct ModelFile
|
||||
{
|
||||
char qcfile[ MAX_PATH ];
|
||||
int version;
|
||||
bool needsrecompile;
|
||||
int toobig;
|
||||
};
|
||||
|
||||
struct AnalysisData
|
||||
{
|
||||
CUtlDict< QCFile, int > files; // .qc to modelname lookup
|
||||
CUtlDict< ModelFile, int > models; // .mdl to .qc/version lookup
|
||||
|
||||
CUtlSymbolTable symbols;
|
||||
};
|
||||
|
||||
static AnalysisData g_Analysis;
|
||||
|
||||
|
||||
SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
|
||||
{
|
||||
printf( "%s", pMsg );
|
||||
OutputDebugString( pMsg );
|
||||
|
||||
if ( type == SPEW_ERROR )
|
||||
{
|
||||
printf( "\n" );
|
||||
OutputDebugString( "\n" );
|
||||
}
|
||||
|
||||
return SPEW_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void printusage( void )
|
||||
{
|
||||
vprint( 0, "usage: mdlcheck <model source directory> <.mdl file directory>\n\
|
||||
\t-v = verbose output\n\
|
||||
\t-l = log to file log.txt\n\
|
||||
\t-a = check for large animation data\n\
|
||||
\ne.g.: mdlcheck -l u:/hl2/hl2/hl2models u:/hl2/hl2/models\n" );
|
||||
|
||||
// Exit app
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension )
|
||||
{
|
||||
WIN32_FIND_DATA wfd;
|
||||
|
||||
char directory[ 256 ];
|
||||
char filename[ 256 ];
|
||||
HANDLE ff;
|
||||
|
||||
sprintf( directory, "%s\\*.*", dir );
|
||||
|
||||
if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
|
||||
return;
|
||||
|
||||
int extlen = strlen( extension );
|
||||
|
||||
do
|
||||
{
|
||||
if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
||||
{
|
||||
|
||||
if ( wfd.cFileName[ 0 ] == '.' )
|
||||
continue;
|
||||
|
||||
// Recurse down directory
|
||||
sprintf( filename, "%s\\%s", dir, wfd.cFileName );
|
||||
BuildFileList_R( files, filename, extension );
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = strlen( wfd.cFileName );
|
||||
if ( len > extlen )
|
||||
{
|
||||
if ( strstr( wfd.cFileName, ".360." ) )
|
||||
{
|
||||
}
|
||||
else if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) )
|
||||
{
|
||||
char filename[ MAX_PATH ];
|
||||
Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName );
|
||||
_strlwr( filename );
|
||||
|
||||
Q_FixSlashes( filename );
|
||||
|
||||
CUtlSymbol sym = g_Analysis.symbols.AddString( filename );
|
||||
files.AddToTail( sym );
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ( FindNextFile( ff, &wfd ) );
|
||||
}
|
||||
|
||||
void BuildFileList( CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension )
|
||||
{
|
||||
files.RemoveAll();
|
||||
BuildFileList_R( files, rootdir, extension );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This is here because scriplib.cpp is included in this project but cmdlib.cpp
|
||||
// is not, but scriplib.cpp uses some stuff from cmdlib.cpp, same with
|
||||
// LoadFile and ExpandPath above. The only thing that currently uses this
|
||||
// is $include in scriptlib, if this function returns 0, $include will
|
||||
// behave the way it did before this change
|
||||
//-----------------------------------------------------------------------------
|
||||
int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool GetModelNameFromSourceFile( char const *filename, char *modelname, int maxlen )
|
||||
{
|
||||
modelname[0]=0;
|
||||
|
||||
int filelength;
|
||||
char *buffer = (char *)COM_LoadFile( filename, &filelength );
|
||||
if ( !buffer )
|
||||
{
|
||||
vprint( 0, "Couldn't load %s\n", filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
|
||||
// Parse tokens
|
||||
char *current = buffer;
|
||||
while ( current )
|
||||
{
|
||||
current = CC_ParseToken( current );
|
||||
if ( strlen( com_token ) <= 0 )
|
||||
break;
|
||||
|
||||
if ( stricmp( com_token, "$modelname" ) )
|
||||
continue;
|
||||
|
||||
current = CC_ParseToken( current );
|
||||
|
||||
strcpy( modelname, com_token );
|
||||
_strlwr( modelname );
|
||||
|
||||
Q_FixSlashes( modelname );
|
||||
|
||||
Q_DefaultExtension( modelname, ".mdl", maxlen );
|
||||
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
COM_FreeFile( (unsigned char *)buffer );
|
||||
|
||||
if ( !valid )
|
||||
{
|
||||
vprint_queued( 0, ".qc file %s missing $modelname directive!!!\n", filename );
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool AddModelNameFromSource( CUtlDict< ModelFile, int >& models, char const *filename, char const *modelname, int offset )
|
||||
{
|
||||
int idx = models.Find( modelname );
|
||||
if ( idx != models.InvalidIndex() )
|
||||
{
|
||||
char shortname[ MAX_PATH ];
|
||||
char shortname2[ MAX_PATH ];
|
||||
strcpy( shortname, &filename[ offset ] );
|
||||
strcpy( shortname2, &models[ idx ].qcfile[ offset ] );
|
||||
|
||||
vprint_queued( 0, "multiple .qc's build %s\n %s\n %s\n",
|
||||
modelname,
|
||||
shortname,
|
||||
shortname2 );
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelFile mf;
|
||||
strcpy( mf.qcfile, filename );
|
||||
_strlwr( mf.qcfile );
|
||||
mf.version = 0;
|
||||
|
||||
models.Insert( modelname, mf );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *sourcetreebase -
|
||||
// *subdir -
|
||||
// *baseentityclass -
|
||||
//-----------------------------------------------------------------------------
|
||||
void ProcessSourceDirectory( char const *basedir )
|
||||
{
|
||||
// vprint( 0, "building .qc list\n" );
|
||||
|
||||
CUtlVector< CUtlSymbol > files;
|
||||
|
||||
BuildFileList( files, basedir, ".qc" );
|
||||
|
||||
// vprint( 0, "found %i .qc files\n\n", files.Count() );
|
||||
|
||||
int offset = strlen( basedir ) + 1;
|
||||
|
||||
// Add files to QC Files dictionary
|
||||
int c = files.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
QCFile qcf;
|
||||
memset( &qcf, 0, sizeof( qcf ) );
|
||||
CUtlSymbol& sym = files[ i ];
|
||||
g_Analysis.files.Insert( g_Analysis.symbols.String( sym ), qcf );
|
||||
}
|
||||
|
||||
vprint_queued( 0, "%s", "\n\n" );
|
||||
|
||||
// Now iterate .qc files, looking into each to find the output model name
|
||||
c = g_Analysis.files.Count();
|
||||
int valid = 0;
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
char modelname[ 256 ];
|
||||
char const *filename = g_Analysis.files.GetElementName( i );
|
||||
if ( verbose )
|
||||
{
|
||||
vprint( 0, "checking %i: %s\n", i, filename );
|
||||
}
|
||||
if ( GetModelNameFromSourceFile( filename, modelname, sizeof( modelname ) ) )
|
||||
{
|
||||
if ( AddModelNameFromSource( g_Analysis.models, filename, modelname, offset ) )
|
||||
{
|
||||
valid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ecount = c - valid;
|
||||
if (ecount != 0)
|
||||
{
|
||||
// vprint( 0, "\n summary: found %i/%i (%.2f percent) .qc errors\n\n", ecount, c, 100.0 * ecount / max( c, 1 ) );
|
||||
vprint( 0, "\n summary: found %i .qc errors\n\n", ecount );
|
||||
}
|
||||
}
|
||||
|
||||
#include "studio.h"
|
||||
|
||||
#define IDSTUDIOHEADER (('T'<<24)+('S'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDST"
|
||||
#define IDSTUDIOANIMGROUPHEADER (('G'<<24)+('A'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDAG"
|
||||
|
||||
|
||||
byte buffer[1024*1024*4];
|
||||
bool ValidateModelFile( char const *modelname, int offset )
|
||||
{
|
||||
studiohdr_t *pHdr;
|
||||
FILE *fp;
|
||||
|
||||
pHdr = (studiohdr_t *)buffer;
|
||||
|
||||
fp = fopen( modelname, "rb" );
|
||||
if ( !fp )
|
||||
{
|
||||
vprint_queued( 0, "Unable to open .mdl file %s\n", modelname );
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if there's a .qc which builds this model
|
||||
char shortname[ MAX_PATH ];
|
||||
strcpy( shortname, &modelname[ offset ] );
|
||||
|
||||
Q_FixSlashes( shortname );
|
||||
|
||||
fread( buffer, sizeof( buffer ), 1, fp );
|
||||
fclose( fp );
|
||||
|
||||
if ( pHdr->id != IDSTUDIOHEADER )
|
||||
{
|
||||
vprint_queued( 0, "Bogus studiomdl header for %s, expecting 'IDST' four cc code\n", shortname );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
bool needsrecompile = false;
|
||||
int toobig = 0;
|
||||
|
||||
// previous version is compatible
|
||||
if ( pHdr->version < 44 || pHdr->version > STUDIO_VERSION )
|
||||
{
|
||||
vprint_queued( 0, "Outdated model %s (ver %i != %i)\n", shortname, pHdr->version, STUDIO_VERSION );
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!Studio_ConvertStudioHdrToNewVersion( pHdr ))
|
||||
{
|
||||
// vprint( 0, "%s needs to be recompiled\n", pHdr->pszName() );
|
||||
needsrecompile = true;
|
||||
}
|
||||
|
||||
if (checkani)
|
||||
{
|
||||
// HACK: since the sequence data is written after the animation data, this is rough way to determine how much anim data there really is
|
||||
int totalanimsize = pHdr->localseqindex - pHdr->localanimindex - pHdr->numlocalanim * sizeof( mstudioanimdesc_t );
|
||||
if (pHdr->pLocalAnimdesc( 0 )->animblock == 0 && totalanimsize > 1024 * 64)
|
||||
{
|
||||
toobig = totalanimsize;
|
||||
}
|
||||
}
|
||||
|
||||
int idx = g_Analysis.models.Find( shortname );
|
||||
if ( idx == g_Analysis.models.InvalidIndex() )
|
||||
{
|
||||
vprint_queued( 0, "Couldn't find a .qc which builds %s\n", shortname );
|
||||
valid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Analysis.models[idx].version = pHdr->version;
|
||||
g_Analysis.models[idx].needsrecompile = needsrecompile;
|
||||
g_Analysis.models[idx].toobig = toobig;
|
||||
}
|
||||
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
void ProcessModelsDirectory( char const *basedir )
|
||||
{
|
||||
// vprint( 0, "building .mdl list\n" );
|
||||
|
||||
CUtlVector< CUtlSymbol > models;
|
||||
|
||||
BuildFileList( models, basedir, ".mdl" );
|
||||
|
||||
// vprint( 0, "found %i .mdl files\n\n", models.Count() );
|
||||
|
||||
int offset = strlen( basedir ) + 1;
|
||||
|
||||
// Now iterate model files and check version tag and whether a .qc exists which builds the .mdl
|
||||
|
||||
vprint_queued( 0, "%s", "\n\n" );
|
||||
|
||||
// Add files to QC Files dictionary
|
||||
int c = models.Count();
|
||||
int valid = 0;
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
QCFile qcf;
|
||||
memset( &qcf, 0, sizeof( qcf ) );
|
||||
CUtlSymbol& sym = models[ i ];
|
||||
|
||||
char const *modelname = g_Analysis.symbols.String( sym );
|
||||
|
||||
if ( verbose )
|
||||
{
|
||||
vprint( 0, "checking %i .mdl %s\n", i, modelname );
|
||||
}
|
||||
|
||||
if ( ValidateModelFile( modelname, offset ) )
|
||||
{
|
||||
valid++;
|
||||
}
|
||||
}
|
||||
|
||||
int ecount = c - valid;
|
||||
if (ecount != 0)
|
||||
{
|
||||
// vprint( 0, "\n summary: found %i/%i (%.2f percent) .mdl errors\n", ecount, c, 100.0 * ecount / max( c, 1 ) );
|
||||
vprint( 0, "\n summary: found %i .mdl errors\n", ecount );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CheckForUnbuiltModels( )
|
||||
{
|
||||
vprint_queued( 0, "%s", "\n\n" );
|
||||
|
||||
int c = g_Analysis.models.Count();
|
||||
int valid = 0;
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
if (g_Analysis.models[i].version == 0)
|
||||
{
|
||||
vprint_queued( 0, "Can't find %s,\n\tbuilt by %s\n", g_Analysis.models.GetElementName( i ), g_Analysis.models[i].qcfile );
|
||||
}
|
||||
else if (g_Analysis.models[i].needsrecompile)
|
||||
{
|
||||
vprint_queued( 0, "%s out of date,\n\tbuilt by %s\n", g_Analysis.models.GetElementName( i ), g_Analysis.models[i].qcfile );
|
||||
}
|
||||
else if (g_Analysis.models[i].toobig)
|
||||
{
|
||||
vprint_queued( 0, "%s needs $animblocksize command (%d of animdata),\n\tbuilt by %s\n", g_Analysis.models.GetElementName( i ), g_Analysis.models[i].toobig, g_Analysis.models[i].qcfile );
|
||||
}
|
||||
else
|
||||
{
|
||||
valid++;
|
||||
}
|
||||
}
|
||||
|
||||
int ecount = c - valid;
|
||||
if (ecount != 0)
|
||||
{
|
||||
// vprint( 0, "\n summary: found %i/%i (%.2f percent) missing .mdl's\n", ecount, c, 100.0 * ecount / max( c, 1 ) );
|
||||
vprint( 0, "\n summary: found %i missing .mdl's\n", ecount );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CheckLogFile( void )
|
||||
{
|
||||
if ( uselogfile )
|
||||
{
|
||||
_unlink( "log.txt" );
|
||||
vprint( 0, " Outputting to log.txt\n" );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : argc -
|
||||
// argv[] -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
SpewOutputFunc( SpewFunc );
|
||||
|
||||
int i = 1;
|
||||
for (i ; i<argc ; i++)
|
||||
{
|
||||
if ( argv[ i ][ 0 ] == '-' )
|
||||
{
|
||||
switch( argv[ i ][ 1 ] )
|
||||
{
|
||||
case 'l':
|
||||
uselogfile = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'a':
|
||||
checkani = true;
|
||||
break;
|
||||
default:
|
||||
printusage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vprint( 0, "Valve Software - mdlcheck.exe (%s)\n", __DATE__ );
|
||||
vprint( 0, "--- Source Model Consistency Checker ---\n" );
|
||||
|
||||
if ( argc < 3 || ( i != argc ) )
|
||||
{
|
||||
printusage();
|
||||
}
|
||||
|
||||
CheckLogFile();
|
||||
|
||||
char modelsources[ 256 ];
|
||||
strcpy( modelsources, argv[ i - 2 ] );
|
||||
char modelsdir[ 256 ];
|
||||
strcpy( modelsdir, argv[ i - 1 ] );
|
||||
|
||||
if ( !strstr( modelsdir, "models" ) )
|
||||
{
|
||||
vprint( 0, "Models dir %s looks invalid (format: u:/tf2/hl2/models)\n", modelsdir );
|
||||
return 0;
|
||||
}
|
||||
|
||||
Q_StripTrailingSlash( modelsources );
|
||||
Q_StripTrailingSlash( modelsdir );
|
||||
|
||||
ProcessSourceDirectory( modelsources );
|
||||
ProcessModelsDirectory( modelsdir );
|
||||
CheckForUnbuiltModels( );
|
||||
|
||||
dump_print_queue( );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// MDLCHECK.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR "..\.."
|
||||
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE,..\common"
|
||||
$Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
|
||||
$PrecompiledHeaderFile "Debug/mdlcheck.pch"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "Mdlcheck"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
-$File "$SRCDIR\public\tier0\memoverride.cpp"
|
||||
$File "mdlcheck.cpp"
|
||||
$File "mdlcheck_util.cpp"
|
||||
$File "StdAfx.cpp"
|
||||
{
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\tier0\basetypes.h"
|
||||
$File "$SRCDIR\public\tier0\commonmacros.h"
|
||||
$File "$SRCDIR\public\tier0\dbg.h"
|
||||
$File "$SRCDIR\public\tier0\fasttimer.h"
|
||||
$File "$SRCDIR\public\mathlib\mathlib.h"
|
||||
$File "mdlcheck_util.h"
|
||||
$File "$SRCDIR\public\tier0\memdbgon.h"
|
||||
$File "$SRCDIR\public\tier0\platform.h"
|
||||
$File "$SRCDIR\public\tier0\protected_things.h"
|
||||
$File "StdAfx.h"
|
||||
$File "$SRCDIR\public\string_t.h"
|
||||
$File "$SRCDIR\public\tier1\strtools.h"
|
||||
$File "$SRCDIR\public\studio.h"
|
||||
$File "$SRCDIR\public\tier1\utldict.h"
|
||||
$File "$SRCDIR\public\tier1\utlmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlrbtree.h"
|
||||
$File "$SRCDIR\public\tier1\utlsymbol.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\public\mathlib\vector.h"
|
||||
$File "$SRCDIR\public\mathlib\vector2d.h"
|
||||
$File "$SRCDIR\public\mathlib\vector4d.h"
|
||||
$File "$SRCDIR\public\vstdlib\vstdlib.h"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "stdafx.h"
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "mdlcheck_util.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
extern bool uselogfile;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : depth -
|
||||
// *fmt -
|
||||
// ... -
|
||||
//-----------------------------------------------------------------------------
|
||||
void vprint( int depth, const char *fmt, ... )
|
||||
{
|
||||
char string[ 8192 ];
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
vsprintf( string, fmt, va );
|
||||
va_end( va );
|
||||
|
||||
FILE *fp = NULL;
|
||||
|
||||
if ( uselogfile )
|
||||
{
|
||||
fp = fopen( "log.txt", "ab" );
|
||||
}
|
||||
|
||||
while ( depth-- > 0 )
|
||||
{
|
||||
printf( " " );
|
||||
OutputDebugString( " " );
|
||||
if ( fp )
|
||||
{
|
||||
fprintf( fp, " " );
|
||||
}
|
||||
}
|
||||
|
||||
::printf( "%s", string );
|
||||
OutputDebugString( string );
|
||||
|
||||
if ( fp )
|
||||
{
|
||||
char *p = string;
|
||||
while ( *p )
|
||||
{
|
||||
if ( *p == '\n' )
|
||||
{
|
||||
fputc( '\r', fp );
|
||||
}
|
||||
fputc( *p, fp );
|
||||
p++;
|
||||
}
|
||||
fclose( fp );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : depth -
|
||||
// *fmt -
|
||||
// ... -
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlVector< char * > printQueue;
|
||||
|
||||
void vprint_queued( int depth, const char *fmt, ... )
|
||||
{
|
||||
char string[ 8192 ];
|
||||
strnset( string, ' ', depth * 2 );
|
||||
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
vsprintf( &string[depth * 2], fmt, va );
|
||||
va_end( va );
|
||||
|
||||
printQueue.AddToTail( strdup( string ) );
|
||||
}
|
||||
|
||||
void dump_print_queue( )
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
|
||||
if ( uselogfile )
|
||||
{
|
||||
fp = fopen( "log.txt", "ab" );
|
||||
}
|
||||
|
||||
for (int i = 0; i < printQueue.Count(); i++)
|
||||
{
|
||||
::printf( "%s", printQueue[i] );
|
||||
OutputDebugString( printQueue[i] );
|
||||
|
||||
if ( fp )
|
||||
{
|
||||
char *p = printQueue[i];
|
||||
while ( *p )
|
||||
{
|
||||
if ( *p == '\n' )
|
||||
{
|
||||
fputc( '\r', fp );
|
||||
}
|
||||
fputc( *p, fp );
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fp)
|
||||
{
|
||||
fclose( fp );
|
||||
}
|
||||
printQueue.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool com_ignorecolons = false; // YWB: Ignore colons as token separators in COM_Parse
|
||||
bool com_ignoreinlinecomment = false;
|
||||
static bool s_com_token_unget = false;
|
||||
char com_token[1024];
|
||||
int linesprocessed = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CC_UngetToken( void )
|
||||
{
|
||||
s_com_token_unget = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ch -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CC_IsBreakChar( char ch )
|
||||
{
|
||||
bool brk = false;
|
||||
switch ( ch )
|
||||
{
|
||||
case '{':
|
||||
case '}':
|
||||
case ')':
|
||||
case '(':
|
||||
case '[':
|
||||
case ']':
|
||||
// case '\'':
|
||||
// case '/':
|
||||
case ',':
|
||||
case ';':
|
||||
case '<':
|
||||
case '>':
|
||||
brk = true;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if ( !com_ignorecolons )
|
||||
brk = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return brk;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *data -
|
||||
// Output : char
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CC_ParseToken(char *data)
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
if ( s_com_token_unget )
|
||||
{
|
||||
s_com_token_unget = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
com_token[0] = 0;
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
// skip whitespace
|
||||
skipwhite:
|
||||
while ( (c = *data) <= ' ')
|
||||
{
|
||||
if (c == 0)
|
||||
return NULL; // end of file;
|
||||
if ( c== '\n' )
|
||||
{
|
||||
linesprocessed++;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
// skip // comments
|
||||
if ( !com_ignoreinlinecomment )
|
||||
{
|
||||
if (c=='/' && data[1] == '/')
|
||||
{
|
||||
while (*data && *data != '\n')
|
||||
data++;
|
||||
goto skipwhite;
|
||||
}
|
||||
}
|
||||
|
||||
if ( c == '/' && data[1] == '*' )
|
||||
{
|
||||
while (data[0] && data[1] && !( data[0] == '*' && data[1] == '/' ) )
|
||||
{
|
||||
if ( *data == '\n' )
|
||||
{
|
||||
linesprocessed++;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
if ( data[0] == '*' && data[1] == '/' )
|
||||
{
|
||||
data+=2;
|
||||
}
|
||||
goto skipwhite;
|
||||
}
|
||||
|
||||
// handle quoted strings specially
|
||||
bool isLstring = data[0] == 'L' && (data[1] == '\"' );
|
||||
if ( isLstring )
|
||||
{
|
||||
com_token[len++] = (char)c;
|
||||
return data+1;
|
||||
}
|
||||
|
||||
if ( c == '\"' )
|
||||
{
|
||||
data++;
|
||||
bool bEscapeSequence = false;
|
||||
while (1)
|
||||
{
|
||||
Assert( len < 1024 );
|
||||
c = *data++;
|
||||
if ( (c=='\"' && !bEscapeSequence) || !c && len < sizeof( com_token ) - 1 )
|
||||
{
|
||||
com_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
bEscapeSequence = ( c == '\\' );
|
||||
com_token[len] = (char)c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
// parse single characters
|
||||
if ( CC_IsBreakChar( (char)c ) )
|
||||
{
|
||||
Assert( len < 1024 );
|
||||
|
||||
com_token[len] = (char)c;
|
||||
len++;
|
||||
com_token[len] = 0;
|
||||
return data+1;
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
Assert( len < 1024 );
|
||||
|
||||
com_token[len] = (char)c;
|
||||
data++;
|
||||
len++;
|
||||
c = *data;
|
||||
|
||||
if ( CC_IsBreakChar( (char)c ) )
|
||||
break;
|
||||
} while (c>32 && len < sizeof( com_token ) - 1);
|
||||
|
||||
com_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
// *len -
|
||||
// Output : unsigned char
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char *COM_LoadFile( const char *name, int *len)
|
||||
{
|
||||
FILE *fp;
|
||||
fp = fopen( name, "rb" );
|
||||
if ( !fp )
|
||||
{
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek( fp, 0, SEEK_END );
|
||||
*len = ftell( fp );
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
|
||||
unsigned char *buffer = new unsigned char[ *len + 1 ];
|
||||
fread( buffer, *len, 1, fp );
|
||||
fclose( fp );
|
||||
buffer[ *len ] = 0;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *buffer -
|
||||
//-----------------------------------------------------------------------------
|
||||
void COM_FreeFile( unsigned char *buffer )
|
||||
{
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *dir -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COM_DirectoryExists( const char *dir )
|
||||
{
|
||||
if ( !_access( dir, 0 ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *input -
|
||||
// Output : char
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CC_ParseUntilEndOfLine( char *input )
|
||||
{
|
||||
while (*input && *input != '\n')
|
||||
input++;
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *input -
|
||||
// *ch -
|
||||
// *breakchar -
|
||||
// Output : char
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CC_RawParseChar( char *input, const char *ch, char *breakchar )
|
||||
{
|
||||
bool done = false;
|
||||
int listlen = strlen( ch );
|
||||
|
||||
do
|
||||
{
|
||||
input = CC_ParseToken( input );
|
||||
if ( strlen( com_token ) <= 0 )
|
||||
break;
|
||||
|
||||
if ( strlen( com_token ) == 1 )
|
||||
{
|
||||
for ( int i = 0; i < listlen; i++ )
|
||||
{
|
||||
if ( com_token[ 0 ] == ch[ i ] )
|
||||
{
|
||||
*breakchar = ch [ i ];
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ( !done );
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *input -
|
||||
// *pairing -
|
||||
// Output : char
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CC_DiscardUntilMatchingCharIncludingNesting( char *input, const char *pairing )
|
||||
{
|
||||
int nestcount = 1;
|
||||
|
||||
do
|
||||
{
|
||||
input = CC_ParseToken( input );
|
||||
if ( strlen( com_token ) <= 0 )
|
||||
break;
|
||||
|
||||
if ( strlen( com_token ) == 1 )
|
||||
{
|
||||
if ( com_token[ 0 ] == pairing[ 0 ] )
|
||||
{
|
||||
nestcount++;
|
||||
}
|
||||
else if ( com_token[ 0 ] == pairing[ 1 ] )
|
||||
{
|
||||
nestcount--;
|
||||
}
|
||||
}
|
||||
} while ( nestcount != 0 );
|
||||
|
||||
return input;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef CLASSCHECK_UTIL_H
|
||||
#define CLASSCHECK_UTIL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
void vprint( int depth, const char *fmt, ... );
|
||||
void vprint_queued( int depth, const char *fmt, ... );
|
||||
void dump_print_queue( void );
|
||||
void CC_UngetToken( void );
|
||||
char *CC_ParseToken(char *data);
|
||||
char *CC_DiscardUntilMatchingCharIncludingNesting( char *input, const char *pairing );
|
||||
char *CC_RawParseChar( char *input, const char *ch, char *breakchar );
|
||||
char *CC_ParseUntilEndOfLine( char *input );
|
||||
|
||||
extern char com_token[1024];
|
||||
extern bool com_ignoreinlinecomment;
|
||||
extern int linesprocessed;
|
||||
|
||||
unsigned char *COM_LoadFile( const char *name, int *len);
|
||||
void COM_FreeFile( unsigned char *buffer );
|
||||
bool COM_DirectoryExists( const char *dir );
|
||||
|
||||
#endif // CLASSCHECK_UTIL_H
|
||||
@@ -0,0 +1,15 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// classcheck.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
@@ -0,0 +1,26 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#if !defined(AFX_STDAFX_H__50E4147E_A508_4D85_BF0A_BA26676063F0__INCLUDED_)
|
||||
#define AFX_STDAFX_H__50E4147E_A508_4D85_BF0A_BA26676063F0__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__50E4147E_A508_4D85_BF0A_BA26676063F0__INCLUDED_)
|
||||
Reference in New Issue
Block a user