mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
1
This commit is contained in:
452
utils/entcount/entcount.cpp
Normal file
452
utils/entcount/entcount.cpp
Normal file
@@ -0,0 +1,452 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: searches through all bsp files in the current directory parsing out entity details
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define max(x,y) ( ((x) > (y)) ? (x) : (y) )
|
||||
|
||||
void SetSearchWord( const char *searchWord );
|
||||
char *FindSearchWord( char *buffer, char *bufend );
|
||||
char *ParseToken( char *data, char *newToken );
|
||||
|
||||
void ClearTable( void );
|
||||
void ClearUsageCountTable( void );
|
||||
void AddToTable( const char *name );
|
||||
void PrintOutTable( void );
|
||||
|
||||
void ParseFGD( char *buffer, char *bufend, const char *searchKey );
|
||||
|
||||
const char *g_UsageString = "usage: entcount [-fgd <fgdfile>] [-nofgd] [-permap] [-onlyent <entname>] [-files <searchmask>]\n";
|
||||
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
if ( argc < 2 )
|
||||
{
|
||||
printf( g_UsageString );
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool printPerMap = false;
|
||||
const char *filterEnt = NULL;
|
||||
const char *fgdFile = NULL;
|
||||
const char *fileMask = "*.bsp";
|
||||
|
||||
// parse the arguments
|
||||
for ( int count = 1; count < argc; count++ )
|
||||
{
|
||||
if ( !stricmp( argv[count], "-permap" ) )
|
||||
{
|
||||
printPerMap = true;
|
||||
}
|
||||
else if ( !stricmp( argv[count], "-onlyent" ) )
|
||||
{
|
||||
count++;
|
||||
if ( count < argc )
|
||||
{
|
||||
filterEnt = argv[count];
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( argv[count], "-fgd" ) )
|
||||
{
|
||||
count++;
|
||||
if ( count < argc )
|
||||
{
|
||||
fgdFile = argv[count];
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( argv[count], "-files" ) )
|
||||
{
|
||||
count++;
|
||||
if ( count < argc )
|
||||
{
|
||||
fileMask = argv[count];
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( argv[count], "-nofgd" ) )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "error: unknown parameter \"%s\"\n", argv[count] );
|
||||
printf( g_UsageString );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// clear the entity accumulator table
|
||||
ClearTable();
|
||||
|
||||
// open and parse the FGD, unless the -nofgd flag is specified
|
||||
if ( fgdFile && !filterEnt && !printPerMap )
|
||||
{
|
||||
FILE *f = fopen( fgdFile, "rb" );
|
||||
if ( !f )
|
||||
{
|
||||
printf( "error: could not open file %s\n", fgdFile );
|
||||
return 2;
|
||||
}
|
||||
|
||||
int filelen;
|
||||
fseek( f, 0, SEEK_END );
|
||||
filelen = ftell( f );
|
||||
fseek( f, 0, SEEK_SET );
|
||||
|
||||
// allocate and load into memory
|
||||
char *buffer = (char*)malloc( filelen );
|
||||
char *bufend = buffer + filelen;
|
||||
fread( buffer, filelen, 1, f );
|
||||
fclose( f );
|
||||
|
||||
// search for all @pointclass, then @solidclass
|
||||
ParseFGD( buffer, bufend, "PointClass" );
|
||||
ParseFGD( buffer, bufend, "SolidClass" );
|
||||
|
||||
// reset the usage counts to 0
|
||||
ClearUsageCountTable();
|
||||
|
||||
free( buffer );
|
||||
}
|
||||
|
||||
// parse through all the bsp files
|
||||
_finddata_t fileinfo;
|
||||
int FHandle = _findfirst( fileMask, &fileinfo );
|
||||
|
||||
if ( FHandle == -1 )
|
||||
{
|
||||
printf( "error: no files found in current directory\n" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
SetSearchWord( "\"classname\"" );
|
||||
|
||||
do {
|
||||
// open the file
|
||||
FILE *f = fopen( fileinfo.name, "rb" );
|
||||
if ( !f )
|
||||
{
|
||||
printf( "error: couldn't open file %s\n", fileinfo.name );
|
||||
return 2;
|
||||
}
|
||||
|
||||
// calculate file length
|
||||
int filelen;
|
||||
fseek( f, 0, SEEK_END );
|
||||
filelen = ftell( f );
|
||||
fseek( f, 0, SEEK_SET );
|
||||
|
||||
// allocate and load into memory
|
||||
char *buffer = (char*)malloc( filelen );
|
||||
char *bufpos = buffer + strlen( "\"classname\"" ) - 1;
|
||||
char *bufend = buffer + filelen;
|
||||
fread( buffer, filelen, 1, f );
|
||||
fclose( f );
|
||||
|
||||
bool entFound = false;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
bufpos = FindSearchWord( bufpos, bufend );
|
||||
if ( !bufpos )
|
||||
break;
|
||||
|
||||
// find the next word
|
||||
static char Token[256];
|
||||
ParseToken( bufpos, Token );
|
||||
|
||||
// add the word to the list, filtering if necessary
|
||||
if ( !filterEnt || !stricmp(filterEnt, Token) )
|
||||
{
|
||||
AddToTable( Token );
|
||||
entFound = true;
|
||||
}
|
||||
|
||||
bufpos += strlen( Token );
|
||||
}
|
||||
|
||||
free( buffer );
|
||||
|
||||
// print the bsp name, if an ent is found, or we are not filtering for ents
|
||||
if ( entFound || !filterEnt )
|
||||
printf( "%s\n", fileinfo.name );
|
||||
|
||||
if ( printPerMap )
|
||||
{
|
||||
PrintOutTable();
|
||||
ClearUsageCountTable();
|
||||
}
|
||||
|
||||
} while ( _findnext(FHandle, &fileinfo) == 0 );
|
||||
|
||||
PrintOutTable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ParseFGD( char *buffer, char *bufend, const char *searchKey )
|
||||
{
|
||||
char *bufpos = buffer + strlen( searchKey ) - 1;
|
||||
SetSearchWord( searchKey );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
bufpos = FindSearchWord( bufpos, bufend );
|
||||
if ( !bufpos )
|
||||
break;
|
||||
|
||||
// search for the corresponding '='
|
||||
while ( *bufpos != '=' )
|
||||
bufpos++;
|
||||
bufpos++;
|
||||
|
||||
// find the classname
|
||||
static char Token[256];
|
||||
ParseToken( bufpos, Token );
|
||||
|
||||
AddToTable( Token );
|
||||
|
||||
bufpos += strlen( Token );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////// entity table stuff //////////////
|
||||
const int MAX_ENTS = 2000;
|
||||
int NumEnts = 0;
|
||||
char *EntNames[ MAX_ENTS ];
|
||||
int EntUsage[ MAX_ENTS ];
|
||||
|
||||
void ClearTable( void )
|
||||
{
|
||||
memset( EntNames, 0, sizeof(EntNames) );
|
||||
memset( EntUsage, 0, sizeof(EntUsage) );
|
||||
}
|
||||
|
||||
void ClearUsageCountTable( void )
|
||||
{
|
||||
memset( EntUsage, 0, sizeof(EntUsage) );
|
||||
}
|
||||
|
||||
void AddToTable( const char *name )
|
||||
{
|
||||
// search for it in the table
|
||||
for ( int i = 0; i < NumEnts; i++ )
|
||||
{
|
||||
if ( EntNames[i] && !strcmp(EntNames[i], name) )
|
||||
{
|
||||
// it's already in the table
|
||||
// increment the usage count
|
||||
EntUsage[i] += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// append to the table
|
||||
EntNames[NumEnts] = (char*)malloc( strlen(name) + 1 );
|
||||
strcpy( EntNames[NumEnts], name );
|
||||
EntUsage[NumEnts] = 1;
|
||||
|
||||
NumEnts++;
|
||||
}
|
||||
|
||||
void PrintOutTable( void )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
// find the highest item
|
||||
int highestUsage = -1;
|
||||
int highestEnt = 0;
|
||||
|
||||
for ( int i = 0; i < NumEnts; i++ )
|
||||
{
|
||||
if ( EntNames[i] && highestUsage < EntUsage[i] )
|
||||
{
|
||||
highestUsage = EntUsage[i];
|
||||
highestEnt = i;
|
||||
}
|
||||
}
|
||||
|
||||
// check for no more ents
|
||||
if ( highestUsage == -1 )
|
||||
return;
|
||||
|
||||
// display usage stats of item
|
||||
printf( " %5d %s\n", highestUsage, EntNames[highestEnt] );
|
||||
|
||||
// remove item from list
|
||||
free( EntNames[highestEnt] );
|
||||
EntNames[highestEnt] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////// string search stuff ////////////
|
||||
|
||||
static unsigned char JumpTable[256];
|
||||
static int SearchWordLen = 0;
|
||||
static const char *SearchWord;
|
||||
|
||||
void SetSearchWord( const char *Word )
|
||||
{
|
||||
SearchWord = Word;
|
||||
SearchWordLen = strlen( SearchWord );
|
||||
|
||||
// build the jump table
|
||||
|
||||
// initialize all values to jump the length of the string
|
||||
memset( JumpTable, SearchWordLen, sizeof(JumpTable) );
|
||||
|
||||
// set the amount the searcher can jump forward, depending on the character
|
||||
for ( int i = 0; i < SearchWordLen; i++ )
|
||||
{
|
||||
JumpTable[ (unsigned char)SearchWord[i] ] = max( SearchWordLen - i - 1, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
char *FindSearchWord( char *buffer, char *bufend )
|
||||
{
|
||||
|
||||
/*
|
||||
for ( int i = SearchWordLen-1; i >= 0; i-- )
|
||||
{
|
||||
if ( *buffer != SearchWord[i] )
|
||||
{
|
||||
buffer += ( JumpTable[ (unsigned char)(*(buffer + i - SearchWordLen + 1)) ] - 1 );
|
||||
|
||||
// no more buffer to search
|
||||
if ( buffer >= bufend )
|
||||
return NULL;
|
||||
|
||||
// reset search counter
|
||||
i = SearchWordLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's a match, move backwards to search
|
||||
buffer--;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( strnicmp(buffer - SearchWordLen, SearchWord, SearchWordLen) )
|
||||
{
|
||||
// strings not equal, jump ahead
|
||||
buffer += JumpTable[ (unsigned char)*buffer ];
|
||||
|
||||
if ( buffer >= bufend )
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we have a match!
|
||||
|
||||
// return a pointer just past the found key
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
ParseToken
|
||||
|
||||
Parse a token out of a string
|
||||
outputs the parsed token into newToken
|
||||
==============
|
||||
*/
|
||||
char *ParseToken( char *data, char *newToken )
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
newToken[0] = 0;
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
// skip whitespace
|
||||
skipwhite:
|
||||
while ( (c = *data) <= ' ')
|
||||
{
|
||||
if (c == 0)
|
||||
return NULL; // end of file;
|
||||
data++;
|
||||
}
|
||||
|
||||
// skip // comments
|
||||
if (c=='/' && data[1] == '/')
|
||||
{
|
||||
while (*data && *data != '\n')
|
||||
data++;
|
||||
goto skipwhite;
|
||||
}
|
||||
|
||||
|
||||
// handle quoted strings specially
|
||||
if (c == '\"')
|
||||
{
|
||||
data++;
|
||||
while ( len < 256 )
|
||||
{
|
||||
c = *data++;
|
||||
if (c=='\"' || !c)
|
||||
{
|
||||
newToken[len] = 0;
|
||||
return data;
|
||||
}
|
||||
newToken[len] = c;
|
||||
len++;
|
||||
}
|
||||
|
||||
if ( len >= 256 )
|
||||
{
|
||||
len--;
|
||||
newToken[len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// parse single characters
|
||||
if ( c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' )
|
||||
{
|
||||
newToken[len] = c;
|
||||
len++;
|
||||
newToken[len] = 0;
|
||||
return data+1;
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
newToken[len] = c;
|
||||
data++;
|
||||
len++;
|
||||
c = *data;
|
||||
if ( c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' )
|
||||
break;
|
||||
|
||||
if ( len >= 256 )
|
||||
{
|
||||
len--;
|
||||
newToken[len] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (c>32);
|
||||
|
||||
newToken[len] = 0;
|
||||
return data;
|
||||
}
|
||||
18
utils/entcount/entcount.vpc
Normal file
18
utils/entcount/entcount.vpc
Normal file
@@ -0,0 +1,18 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// ENTCOUNT.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR "..\.."
|
||||
$Macro OUTBINDIR "$SRCDIR\devtools\bin"
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
|
||||
|
||||
$Project "Entcount"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "entcount.cpp"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user