summaryrefslogtreecommitdiff
path: root/utils/classcheck/class.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/classcheck/class.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'utils/classcheck/class.cpp')
-rw-r--r--utils/classcheck/class.cpp1581
1 files changed, 1581 insertions, 0 deletions
diff --git a/utils/classcheck/class.cpp b/utils/classcheck/class.cpp
new file mode 100644
index 0000000..369aa74
--- /dev/null
+++ b/utils/classcheck/class.cpp
@@ -0,0 +1,1581 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include <assert.h>
+#include "stdafx.h"
+#include <stdio.h>
+#include <windows.h>
+#include "classcheck_util.h"
+#include "class.h"
+#include "icodeprocessor.h"
+
+CClass::CClass( const char *name )
+{
+ m_nVarCount = 0;
+ m_nMemberCount = 0;
+ m_nTDCount = 0;
+ m_nPredTDCount = 0;
+
+ strcpy( m_szName, name );
+ m_szBaseClass[0]=0;
+ m_pBaseClass = NULL;
+ m_szTypedefBaseClass[0]=0;
+
+ m_bDerivedFromCBaseEntity = false;
+ m_bHasSaveRestoreData = false;
+ m_bHasPredictionData = false;
+ m_bConstructPredictableCalled = false;
+ m_bHasRecvTableData = false;
+
+ m_nClassDataSize = 0;
+}
+
+CClass::~CClass( void )
+{
+ int i;
+
+ for ( i = 0; i < m_nVarCount; i++ )
+ {
+ delete m_Variables[ i ];
+ }
+ m_nVarCount = 0;
+
+ for ( i = 0; i < m_nMemberCount; i++ )
+ {
+ delete m_Members[ i ];
+ }
+ m_nMemberCount = 0;
+ for ( i = 0; i < m_nTDCount; i++ )
+ {
+ delete m_TDFields[ i ];
+ }
+ m_nTDCount = 0;
+ for ( i = 0; i < m_nPredTDCount; i++ )
+ {
+ delete m_PredTDFields[ i ];
+ }
+ m_nPredTDCount = 0;
+}
+
+CTypeDescriptionField *CClass::FindTD( const char *name )
+{
+ for ( int i = 0; i < m_nTDCount; i++ )
+ {
+ if ( !strcmp( m_TDFields[ i ]->m_szVariableName, name ) )
+ return m_TDFields[ i ];
+ }
+ return NULL;
+}
+
+CTypeDescriptionField *CClass::FindPredTD( const char *name )
+{
+ for ( int i = 0; i < m_nPredTDCount; i++ )
+ {
+ if ( !strcmp( m_PredTDFields[ i ]->m_szVariableName, name ) )
+ return m_PredTDFields[ i ];
+ }
+ return NULL;
+}
+
+CClassVariable *CClass::FindVar( const char *name, bool checkbaseclasses /*= false*/ )
+{
+ CClass *cl = this;
+ while ( cl )
+ {
+ for ( int i = 0; i < cl->m_nVarCount; i++ )
+ {
+ if ( !strcmp( cl->m_Variables[ i ]->m_szName, name ) )
+ return cl->m_Variables[ i ];
+ }
+
+ if ( !checkbaseclasses )
+ break;
+
+ if ( !cl->m_pBaseClass )
+ {
+ cl->m_pBaseClass = processor->FindClass( cl->m_szBaseClass );
+ }
+
+ cl = cl->m_pBaseClass;
+ if ( !cl )
+ break;
+ }
+ return NULL;
+}
+
+CClassMemberFunction *CClass::FindMember( const char *name )
+{
+ for ( int i = 0; i < m_nMemberCount; i++ )
+ {
+ if ( !strcmp( m_Members[ i ]->m_szName, name ) )
+ return m_Members[ i ];
+ }
+ return NULL;
+}
+
+CTypeDescriptionField *CClass::AddTD( const char *name, const char *type, const char *definetype, bool incomments )
+{
+ CTypeDescriptionField *td = FindTD( name );
+ if ( !td )
+ {
+ td = new CTypeDescriptionField();
+ strcpy( td->m_szVariableName, name );
+ strcpy( td->m_szType, type );
+ strcpy( td->m_szDefineType, definetype );
+ td->m_bCommentedOut = incomments;
+
+ m_TDFields[ m_nTDCount++ ] = td;
+ if ( m_nTDCount >= MAX_TDFIELDS )
+ {
+ vprint( 0, "too many typedescription fields\n" );
+ exit( 1 );
+ }
+ }
+ return td;
+}
+
+CTypeDescriptionField *CClass::AddPredTD( const char *name, const char *type, const char *definetype, bool incomments, bool inrecvtable )
+{
+ CTypeDescriptionField *td = FindPredTD( name );
+ if ( !td )
+ {
+ td = new CTypeDescriptionField();
+ strcpy( td->m_szVariableName, name );
+ strcpy( td->m_szType, type );
+ strcpy( td->m_szDefineType, definetype );
+ td->m_bCommentedOut = incomments;
+ td->m_bRepresentedInRecvTable = inrecvtable;
+
+ m_PredTDFields[ m_nPredTDCount++ ] = td;
+ if ( m_nPredTDCount >= MAX_TDFIELDS )
+ {
+ vprint( 0, "too many prediction typedescription fields\n" );
+ exit( 1 );
+ }
+ }
+ return td;
+}
+
+CClassVariable *CClass::AddVar( const char *name )
+{
+ CClassVariable *var = FindVar( name );
+ if ( !var )
+ {
+ var = new CClassVariable();
+ strcpy( var->m_szName, name );
+
+ m_Variables[ m_nVarCount++ ] = var;
+ if ( m_nVarCount >= MAX_VARIABLES )
+ {
+ vprint( 0, "too many variables\n" );
+ exit( 1 );
+ }
+ }
+ return var;
+}
+
+CClassMemberFunction *CClass::AddMember( const char *name )
+{
+ CClassMemberFunction *member = FindMember( name );
+ if ( !member )
+ {
+ member = new CClassMemberFunction();
+ strcpy( member->m_szName, name );
+
+ m_Members[ m_nMemberCount++ ] = member;
+ if ( m_nMemberCount >= MAX_MEMBERS )
+ {
+ vprint( 0, "too many members\n" );
+ exit( 1 );
+ }
+ }
+ return member;
+}
+
+void CClass::SetBaseClass( const char *name )
+{
+ if ( !m_szBaseClass[ 0 ] )
+ {
+ strcpy( m_szBaseClass, name );
+ }
+ else if ( stricmp( m_szBaseClass, name ) )
+ {
+ vprint( 0, "Base class differs for %s %s vs %s\n", m_szName, m_szBaseClass, name );
+ }
+}
+
+void CClass::CheckChildOfBaseEntity( const char *baseentityclass )
+{
+ m_bDerivedFromCBaseEntity = false;
+
+ if ( !stricmp( m_szName, baseentityclass ) )
+ {
+ m_bDerivedFromCBaseEntity = true;
+ return;
+ }
+
+ CClass *base = m_pBaseClass;
+ while ( base )
+ {
+ // Early out?
+ if ( base->m_bDerivedFromCBaseEntity )
+ {
+ m_bDerivedFromCBaseEntity = true;
+ return;
+ }
+
+ // Check name
+ if ( !stricmp( base->m_szName, baseentityclass ) )
+ {
+ m_bDerivedFromCBaseEntity = true;
+ return;
+ }
+
+ // Keep going up hierarchy
+ base = base->m_pBaseClass;
+ }
+}
+
+static bool IsType( char *input, char *test )
+{
+ char *pMatch = strstr( input, test );
+ if ( !pMatch )
+ return false;
+
+ size_t nLen = strlen(test);
+ if ( ( pMatch[nLen] != 0 ) && (pMatch[nLen] != ' ') )
+ return false;
+
+ if ( input != pMatch && (*(pMatch-1) != ' ') )
+ return false;
+
+ return true;
+}
+
+static char const *TranslateSimpleType( CClassVariable *var )
+{
+ static char out[ 256 ];
+ out[ 0 ] = 0;
+
+ char *input = var->m_szType;
+
+ // Don't know how to handle templatized things yet
+ if ( strstr( input, "<" ) )
+ {
+ return out;
+ }
+
+ if ( IsType( input, "bool" ) )
+ {
+ return "FIELD_BOOLEAN";
+ }
+ else if ( IsType( input, "short" ) )
+ {
+ return "FIELD_SHORT";
+ }
+ else if ( IsType( input, "int" ) )
+ {
+ return "FIELD_INTEGER";
+ }
+ else if ( IsType( input, "byte" ) )
+ {
+ return "FIELD_CHARACTER";
+ }
+ else if ( IsType( input, "float" ) )
+ {
+ return "FIELD_FLOAT";
+ }
+ else if ( IsType( input, "EHANDLE" ) || IsType( input, "CHandle" ) )
+ {
+ return "FIELD_EHANDLE";
+ }
+ else if ( IsType( input, "color32" ) )
+ {
+ return "FIELD_COLOR32";
+ }
+ else if ( IsType( input, "Vector" ) || IsType( input, "QAngle" ) )
+ {
+ return "FIELD_VECTOR";
+ }
+ else if ( IsType( input, "Quaternion" ) )
+ {
+ return "FIELD_QUATERNION";
+ }
+ else if ( IsType( input, "VMatrix" ) )
+ {
+ return "FIELD_VMATRIX";
+ }
+ else if ( IsType( input, "string_t" ) )
+ {
+ return "FIELD_STRING";
+ }
+ else if ( IsType( input, "char" ) )
+ {
+ return "FIELD_CHARACTER";
+ }
+
+ return out;
+}
+
+void CClass::ReportTypeMismatches( CClassVariable *var, CTypeDescriptionField *td )
+{
+ char const *t = TranslateSimpleType( var );
+ if ( !t[0] )
+ return;
+
+ // Special cases
+ if ( td->m_bCommentedOut )
+ return;
+
+ if ( !strcmp( td->m_szType, "FIELD_TIME" ) )
+ {
+ if ( !strcmp( t, "FIELD_FLOAT" ) )
+ return;
+ }
+
+ if ( !strcmp( td->m_szType, "FIELD_TICK" ) )
+ {
+ if ( !strcmp( t, "FIELD_INTEGER" ) )
+ return;
+ }
+
+ if ( !strcmp( td->m_szType, "FIELD_MODELNAME" ) || !strcmp( td->m_szType, "FIELD_SOUNDNAME" ) )
+ {
+ if ( !strcmp( t, "FIELD_STRING" ) )
+ return;
+ }
+
+ if ( !strcmp( td->m_szType, "FIELD_MODELINDEX" ) || !strcmp( td->m_szType, "FIELD_MATERIALINDEX" ) )
+ {
+ if ( !strcmp( t, "FIELD_INTEGER" ) )
+ return;
+ }
+
+ if ( !strcmp( td->m_szType, "FIELD_POSITION_VECTOR" ) )
+ {
+ if ( !strcmp( t, "FIELD_VECTOR" ) )
+ return;
+ }
+
+ if ( !strcmp( td->m_szType, "FIELD_VMATRIX_WORLDSPACE" ) )
+ {
+ if ( !strcmp( t, "FIELD_VMATRIX" ) )
+ return;
+ }
+
+ if ( strcmp( t, td->m_szType ) )
+ {
+ vprint( 0, "class %s has an incorrect FIELD_ type for variable '%s (%s, %s)'\n",
+ m_szName, var->m_szName, var->m_szType, td->m_szType );
+ }
+}
+
+
+bool CClass::CheckForMissingTypeDescriptionFields( int& missingcount, bool createtds )
+{
+ bool bret = false;
+ missingcount = 0;
+ // Didn't specify a TYPEDESCRIPTION at all
+ if ( !m_bHasSaveRestoreData )
+ return bret;
+
+ for ( int i = 0; i < m_nVarCount; i++ )
+ {
+ CClassVariable *var = m_Variables[ i ];
+
+ bool isstatic = false;
+ char *p = var->m_szType;
+ while ( 1 )
+ {
+ p = CC_ParseToken( p );
+ if ( strlen( com_token ) <= 0 )
+ break;
+ if ( !stricmp( com_token, "static" ) )
+ {
+ isstatic = true;
+ break;
+ }
+ }
+
+ // Statics aren't encoded
+ if ( isstatic )
+ continue;
+
+ char *goodname = var->m_szName;
+
+ // Skip * pointer modifier
+ while ( *goodname && *goodname == '*' )
+ {
+ goodname++;
+ }
+
+ CTypeDescriptionField *td = FindTD( goodname );
+ if ( td )
+ {
+ ReportTypeMismatches( var, td );
+ continue;
+ }
+
+ bret = true;
+ missingcount++;
+
+ if ( !createtds )
+ {
+ vprint( 0, "class %s missing typedescription_t field for variable '%s %s'\n",
+ m_szName, var->m_szType, var->m_szName );
+ continue;
+ }
+
+ char const *t = TranslateSimpleType( var );
+
+ vprint( 0, "//\tClass %s:\n", m_szName );
+ if ( var->m_bIsArray &&
+ (
+ stricmp( var->m_szType, "char" ) ||
+ stricmp( t, "FIELD_STRING" )
+ ) )
+ {
+ if ( *t )
+ {
+ vprint( 0, "\tDEFINE_ARRAY( %s, %s, %s ),\n", goodname, t, var->m_szArraySize );
+ }
+ else
+ {
+ vprint( 0, "\t// DEFINE_ARRAY( %s, %s, %s ),\n", goodname, var->m_szType, var->m_szArraySize );
+ }
+ }
+ else
+ {
+ if ( *t )
+ {
+ vprint( 0, "\tDEFINE_FIELD( %s, %s ),\n", goodname, t );
+ }
+ else
+ {
+ vprint( 0, "\t// DEFINE_FIELD( %s, %s ),\n", goodname, var->m_szType );
+ }
+ }
+ }
+
+ return bret;
+}
+
+bool CClass::CheckForPredictionFieldsInRecvTableNotMarkedAsSuchCorrectly( int &missingcount )
+{
+ bool bret = false;
+ missingcount = 0;
+ // Didn't specify a TYPEDESCRIPTION at all
+ if ( !m_bHasPredictionData )
+ return bret;
+
+ if ( !m_bHasRecvTableData )
+ return bret;
+
+ for ( int i = 0; i < m_nVarCount; i++ )
+ {
+ CClassVariable *var = m_Variables[ i ];
+ bool inreceivetable = var->m_bInRecvTable;
+
+ bool isstatic = false;
+ char *p = var->m_szType;
+ while ( 1 )
+ {
+ p = CC_ParseToken( p );
+ if ( strlen( com_token ) <= 0 )
+ break;
+ if ( !stricmp( com_token, "static" ) )
+ {
+ isstatic = true;
+ break;
+ }
+ }
+
+ // Statics aren't encoded
+ if ( isstatic )
+ continue;
+
+ char *goodname = var->m_szName;
+
+ // Skip * pointer modifier
+ while ( *goodname && *goodname == '*' )
+ goodname++;
+
+ CTypeDescriptionField *td = FindPredTD( goodname );
+ // Missing variables are caught in a different routine
+ td = FindPredTD( goodname );
+ if ( !td )
+ continue;
+
+ // These are implicitly ok
+ if ( !strcmp( td->m_szDefineType, "DEFINE_PRED_TYPEDESCRIPTION" ) )
+ {
+ CClass *cl2 = processor->FindClass( td->m_szType );
+ if ( cl2 )
+ {
+ bret = cl2->CheckForPredictionFieldsInRecvTableNotMarkedAsSuchCorrectly( missingcount );
+ }
+ continue;
+ }
+
+ // Looks good (either in or out!)
+ // Check for appripriate flags
+ if ( inreceivetable == td->m_bRepresentedInRecvTable )
+ continue;
+
+ bret = true;
+ missingcount++;
+
+ if ( inreceivetable && !td->m_bRepresentedInRecvTable )
+ {
+ vprint( 0, "%s::%s: Missing FTYPEDESC_INSENDTABLE flag in prediction typedescription\n", m_szName, var->m_szName );
+ }
+ else
+ {
+ vprint( 0, "%s::%s: Field marked as FTYPEDESC_INSENDTABLE in prediction typedescription missing from RecvTable\n", m_szName, var->m_szName );
+ }
+ }
+
+ return bret;
+}
+
+bool CClass::CheckForMissingPredictionFields( int& missingcount, bool createtds )
+{
+ bool bret = false;
+ missingcount = 0;
+ // Didn't specify a TYPEDESCRIPTION at all
+ if ( !m_bHasPredictionData )
+ return bret;
+
+ for ( int i = 0; i < m_nVarCount; i++ )
+ {
+ CClassVariable *var = m_Variables[ i ];
+
+ // private and protected variables can't be referenced in data tables right now
+ //if ( var->m_Type != CClassVariable::TPUBLIC )
+ // continue;
+
+ bool isstatic = false;
+ char *p = var->m_szType;
+ while ( 1 )
+ {
+ p = CC_ParseToken( p );
+ if ( strlen( com_token ) <= 0 )
+ break;
+ if ( !stricmp( com_token, "static" ) )
+ {
+ isstatic = true;
+ break;
+ }
+ }
+
+ // Statics aren't encoded
+ if ( !isstatic )
+ {
+ char *goodname = var->m_szName;
+
+ // Skip * pointer modifier
+ while ( *goodname && *goodname == '*' )
+ goodname++;
+
+ CTypeDescriptionField *td = FindPredTD( goodname );
+ td = FindPredTD( goodname );
+ if ( !td )
+ {
+ bret = true;
+ missingcount++;
+
+ if ( !createtds )
+ {
+ vprint( 0, "class %s missing prediction typedescription_t field for variable '%s %s'\n",
+ m_szName, var->m_szType, var->m_szName );
+ }
+ else
+ {
+ char const *t = TranslateSimpleType( var );
+
+ vprint( 0, "//\tClass %s:\n", m_szName );
+ if ( var->m_bIsArray &&
+ (
+ stricmp( var->m_szType, "char" ) ||
+ stricmp( t, "FIELD_STRING" )
+ ) )
+ {
+ if ( *t )
+ {
+ vprint( 0, "\tDEFINE_ARRAY( %s, %s, %s ),\n", goodname, t, var->m_szArraySize );
+ }
+ else
+ {
+ vprint( 0, "\t// DEFINE_ARRAY( %s, %s, %s ),\n", goodname, var->m_szType, var->m_szArraySize );
+ }
+ }
+ else
+ {
+ if ( *t )
+ {
+ vprint( 0, "\tDEFINE_FIELD( %s, %s ),\n", goodname, t );
+ }
+ else
+ {
+ vprint( 0, "\t// DEFINE_FIELD( %s, %s ),\n", goodname, var->m_szType );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return bret;
+}
+
+void AppendType( const char *token, char *type )
+{
+ strcat( type, token );
+ strcat( type, " " );
+}
+
+class MissingType
+{
+public:
+ CClass *owning_class;
+ CClassVariable *var;
+};
+
+#include "utldict.h"
+CUtlDict< MissingType, unsigned short > missing_types;
+
+bool IsMissingType( CClass *cl, CClassVariable *var )
+{
+ unsigned short lookup;
+
+ lookup = missing_types.Find( var->m_szType );
+ if ( lookup != missing_types.InvalidIndex() )
+ return true;
+
+ MissingType t;
+ t.owning_class = cl;
+ t.var = var;
+ missing_types.Insert( var->m_szType, t );
+ return true;
+}
+
+void ReportMissingTypes( void )
+{
+ int c = missing_types.Count();
+ for ( int i= 0; i < c; i++ )
+ {
+ MissingType *t = &missing_types[ i ];
+ if ( !t )
+ continue;
+
+ if ( !t->owning_class )
+ continue;
+
+ if ( !t->owning_class->m_bDerivedFromCBaseEntity )
+ continue;
+
+ if ( !t->var )
+ continue;
+
+ vprint( 0, "Can't compute size of %s %s %s\n",
+ t->owning_class->m_szName, t->var->m_szType, t->var->m_szName );
+ }
+}
+
+void ClearMissingTypes()
+{
+ missing_types.Purge();
+}
+
+static int GetTypeSize( CClass *cl, CClassVariable *var )
+{
+ int out = 0;
+
+ char *input = var->m_szType;
+
+ // Don't know how to handle templatized things yet
+ if ( strstr( input, "<" ) )
+ {
+ IsMissingType( cl, var );
+ return out;
+ }
+
+ if ( strstr( var->m_szName, "*" ) )
+ {
+ return sizeof( void * );
+ }
+
+ if ( strstr( input, "bool" ) )
+ {
+ return sizeof( bool );
+ }
+ else if ( strstr( input, "int64" ) )
+ {
+ return sizeof( __int64 );
+ }
+ else if ( strstr( input, "short" ) )
+ {
+ return sizeof( short );
+ }
+ else if ( strstr( input, "unsigned short" ) )
+ {
+ return sizeof( unsigned short );
+ }
+ else if ( strstr( input, "int" ) )
+ {
+ return sizeof( int );
+ }
+ else if ( strstr( input, "float" ) )
+ {
+ return sizeof( float );
+ }
+ else if ( strstr( input, "vec_t" ) )
+ {
+ return sizeof( float );
+ }
+ else if ( strstr( input, "Vector" ) || strstr( input, "QAngle" ) )
+ {
+ return 3 * sizeof( float );
+ }
+ else if ( strstr( input, "vec3_t" ) )
+ {
+ return 3 * sizeof( float );
+ }
+ else if ( strstr( input, "char" ) )
+ {
+ return sizeof( char );
+ }
+ else if ( strstr( input, "unsigned char" ) )
+ {
+ return sizeof( unsigned char );
+ }
+ else if ( strstr( input, "BYTE" ) )
+ {
+ return sizeof( char );
+ }
+ else if ( strstr( input, "byte" ) )
+ {
+ return sizeof( char );
+ }
+ else if ( !strcmp( input, "unsigned" ) )
+ {
+ return sizeof(unsigned int);
+ }
+ else if ( strstr( input, "long" ) )
+ {
+ return sizeof( int );
+ }
+ else if ( strstr( input, "color32" ) )
+ {
+ return sizeof( int );
+ }
+ // It's a pointer
+ else if ( strstr( input, "*" ) )
+ {
+ return sizeof( void * );
+ }
+ // Static data doesn't count
+ else if ( strstr( input, "static" ) )
+ {
+ return 0;
+ }
+
+
+ // Okay, see if it's a classname
+ CClass *base = processor->FindClass( input );
+ if ( base )
+ {
+ return base->m_nClassDataSize;
+ }
+
+ IsMissingType( cl, var );
+
+ return out;
+}
+
+
+void CClass::AddVariable( int protection, char *type, char *name, bool array, char *arraysize )
+{
+ CClassVariable *var = AddVar( name );
+ if ( !var )
+ return;
+
+ strcpy( var->m_szType, type );
+ var->m_Type = (CClassVariable::VARTYPE)protection;
+ var->m_TypeSize = GetTypeSize( this, var );
+
+ m_nClassDataSize += var->m_TypeSize;
+
+ if ( array )
+ {
+ var->m_bIsArray = true;
+ strcpy( var->m_szArraySize, arraysize );
+ }
+ else
+ {
+ var->m_bIsArray = false;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Parses information to determine the base class of this class
+//-----------------------------------------------------------------------------
+bool CClass::ParseBaseClass( char *&input )
+{
+ if ( !strcmp( com_token, "DECLARE_CLASS" )
+ || !strcmp( com_token, "DECLARE_CLASS_GAMEROOT" )
+ || !strcmp( com_token, "DECLARE_CLASS_NOFRIEND" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+ input = CC_ParseToken( input );
+
+ do
+ {
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ",") );
+
+ m_szTypedefBaseClass[0] = 0;
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( m_szTypedefBaseClass, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+ return true;
+ }
+ else if ( !strcmp( com_token, "DECLARE_CLASS_NOBASE" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+ input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Parses networkvars
+//-----------------------------------------------------------------------------
+bool CClass::ParseNetworkVar( char *&input, int protection )
+{
+ MemberVarParse_t var;
+
+ if ( !strcmp( com_token, "CNetworkVar" ) ||
+ !strcmp( com_token, "CNetworkVarForDerived" ) ||
+ !strcmp( com_token, "CNetworkVarEmbedded" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pType, com_token );
+ strcat( var.m_pType, " " );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ",") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pName, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+
+ AddVariable( protection, var.m_pType, var.m_pName, false );
+ return true;
+ }
+
+ if ( !strcmp( com_token, "CNetworkHandle" ) || !strcmp( com_token, "CNetworkHandleForDerived" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+
+ input = CC_ParseToken( input );
+ strcpy( var.m_pType, "CHandle<" );
+ do
+ {
+ strcat( var.m_pType, com_token );
+ strcat( var.m_pType, " " );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ",") );
+ strcat( var.m_pType, ">" );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pName, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+
+ AddVariable( protection, "EHANDLE", var.m_pName, false );
+ return true;
+ }
+
+ if ( !strcmp( com_token, "CNetworkVector" ) ||
+ !strcmp( com_token, "CNetworkVectorForDerived" ) ||
+ !strcmp( com_token, "CNetworkQAngle" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pName, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+
+ AddVariable( protection, "Vector", var.m_pName, false );
+ return true;
+ }
+
+ if ( !strcmp( com_token, "CNetworkColor32" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pName, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+
+ AddVariable( protection, "color32", var.m_pName, false );
+ return true;
+ }
+
+ if ( !strcmp( com_token, "CNetworkString" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pName, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ",") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pArraySize, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+
+ AddVariable( protection, "char *", var.m_pName, true, var.m_pArraySize );
+ return true;
+ }
+
+ if ( !strcmp( com_token, "CNetworkArray" ) || !strcmp( com_token, "CNetworkArrayForDerived" ) )
+ {
+ input = CC_ParseToken( input );
+ Assert( !strcmp( com_token, "(") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pType, com_token );
+ strcat( var.m_pType, " " );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ",") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pName, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ",") );
+
+ input = CC_ParseToken( input );
+ do
+ {
+ strcat( var.m_pArraySize, com_token );
+ input = CC_ParseToken( input );
+ } while( strcmp( com_token, ")") );
+
+ AddVariable( protection, var.m_pType, var.m_pName, true, var.m_pArraySize );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Parses a class member definition
+//-----------------------------------------------------------------------------
+bool CClass::ParseClassMember( char *&input, int protection )
+{
+ MemberVarParse_t var;
+
+ bool isfunction = false;
+ bool wascomma = false;
+ bool skipvar = false;
+
+ if ( ParseNetworkVar( input, protection ) )
+ return true;
+
+ strcpy( var.m_pName, com_token );
+ if ( !stricmp( var.m_pName, "SHARED_CLASSNAME" ) )
+ {
+ input = CC_ParseToken( input );
+ if ( !stricmp( com_token, "(" ) )
+ {
+ char inside[ 256 ];
+ char *saveinput = input;
+ input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
+
+ int len = input - saveinput;
+ strncpy( inside, saveinput, len );
+ inside[ len ] =0;
+
+ strcat( var.m_pName, "(" );
+ strcat( var.m_pName, inside );
+ }
+ }
+
+ do
+ {
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ if ( !stricmp( com_token, "(" ) )
+ {
+ char *saveinput = input;
+
+ isfunction = true;
+
+ input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
+
+ // see if the function is being declared in line here
+ input = CC_ParseToken( input );
+
+ if ( !stricmp( com_token, "const" ) )
+ {
+ // Swallow const if we see it
+ input = CC_ParseToken( input );
+ }
+
+ if ( !stricmp( com_token, "{" ) )
+ {
+ input = CC_DiscardUntilMatchingCharIncludingNesting( input, "{}" );
+ }
+ // pure virtual function?
+ else if ( !stricmp( com_token, "=" ) )
+ {
+ char ch;
+ input = CC_RawParseChar( input, ";", &ch );
+ }
+ // this was a pointer to a base function
+ else if ( !stricmp( com_token, "(" ) )
+ {
+ char *end = input - 2;
+ input = saveinput;
+
+ char pfn[ 256 ];
+ int len = end - saveinput;
+ strncpy( pfn, input, len );
+ pfn[ len ] = 0;
+
+ do
+ {
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ if ( com_token[0] == '*' )
+ {
+ break;
+ }
+ } while ( 1 );
+
+ if ( com_token[0] == '*' )
+ {
+ // com_token is the variable name
+ sprintf( var.m_pType, "%s (%s)", var.m_pName, pfn );
+ strcpy( var.m_pName, com_token );
+ input = end + 1;
+ }
+
+ if ( *input == '(' )
+ input++;
+ input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
+
+ isfunction = false;
+ }
+
+ break;
+ }
+ else if ( !stricmp( com_token, "[" ) )
+ {
+ // It's an array
+ var.m_bArray = true;
+ char ch;
+ char *oldinput = input;
+ do
+ {
+ input = CC_RawParseChar( input, "]", &ch );
+ if ( *input && ( *input == '[' ) )
+ {
+ input++;
+ continue;
+ }
+
+ break;
+ } while ( 1 );
+ int len = input-oldinput - 1;
+ if ( len > 0 )
+ {
+ strncpy( var.m_pArraySize, oldinput, len );
+ }
+ var.m_pArraySize[ len ] = 0;
+ break;
+ }
+ else if ( !stricmp( com_token, ";" ) )
+ {
+ break;
+ }
+ else if ( !stricmp( com_token, ":" ) && !isfunction )
+ {
+ // Eliminate the length specification
+ input = CC_ParseToken( input );
+ continue;
+ }
+ else if ( !stricmp( com_token, "," ) )
+ {
+ wascomma = true;
+ break;
+ }
+ // It's a templatized var
+ else if (( com_token[ strlen( com_token ) - 1 ] == '<' ) && strcmp(var.m_pName, "operator") )
+ {
+ do
+ {
+ AppendType( var.m_pName, var.m_pType );
+ strcpy( var.m_pName, com_token );
+
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) <= 0 )
+ break;
+ }
+ while ( strcmp( com_token, ">" ) );
+
+ AppendType( var.m_pName, var.m_pType );
+ strcpy( var.m_pName, com_token );
+ }
+ else
+ {
+ if ( !stricmp( var.m_pName, "typedef" ) ||
+ !stricmp( var.m_pName, "enum" ) ||
+ !stricmp( var.m_pName, "friend" ) )
+ {
+ skipvar = true;
+ }
+ AppendType( var.m_pName, var.m_pType );
+ strcpy( var.m_pName, com_token );
+ continue;
+ }
+
+ } while ( 1 );
+
+ if ( strlen( var.m_pType ) >= 1 )
+ {
+ var.m_pType[ strlen( var.m_pType ) - 1 ] = 0;
+ }
+
+ if ( var.m_pType[0]==0 &&
+ ( !strcmp( var.m_pName, "CUSTOM_SCHEDULES" ) ||
+ !strcmp( var.m_pName, "DEFINE_CUSTOM_SCHEDULE_PROVIDER" ) ||
+ !strcmp( var.m_pName, "DEFINE_CUSTOM_AI" ) ||
+ !strcmp( var.m_pName, "DECLARE_DATADESC" ) ||
+ !strcmp( var.m_pName, "DECLARE_EMBEDDED_DATADESC" ) ||
+ !strcmp( var.m_pName, "DECLARE_SERVERCLASS" ) ||
+ !strcmp( var.m_pName, "DECLARE_CLIENTCLASS" ) ||
+ !strcmp( var.m_pName, "DECLARE_ENTITY_PANEL" ) ||
+ !strcmp( var.m_pName, "DECLARE_MINIMAP_PANEL" ) ||
+ !strcmp( var.m_pName, "MANUALMODE_GETSET_PROP" ) ) )
+ {
+ return true;
+ }
+
+ if ( var.m_pType[0]==0 &&
+ ( !strcmp( var.m_pName, "DECLARE_PREDICTABLE" ) ||
+ !strcmp( var.m_pName, "DECLARE_EMBEDDED_PREDDESC" ) ) )
+ {
+ m_bHasPredictionData = true;
+ return true;
+ }
+
+ /*
+ if ( var.m_pName[0] == '*' )
+ {
+ strcat( type, " *" );
+
+ char newname[ 256 ];
+ strcpy( newname, &var.m_pName[1] );
+ strcpy( var.m_pName, newname );
+ }
+ */
+
+ if ( isfunction )
+ {
+ CClassMemberFunction *member = AddMember( var.m_pName );
+ if ( member )
+ {
+ strcpy( member->m_szType, var.m_pType );
+ member->m_Type = (CClassMemberFunction::MEMBERTYPE)protection;
+ }
+ }
+ else
+ {
+ // It's a variable
+ do
+ {
+ if ( !skipvar )
+ {
+ AddVariable( protection, var.m_pType, var.m_pName, var.m_bArray, var.m_pArraySize );
+ }
+ else if ( !stricmp( var.m_pName, "BaseClass" ) )
+ {
+ if ( !m_szTypedefBaseClass[0] )
+ {
+ char *p = var.m_pType;
+ p = CC_ParseToken( p );
+ p = CC_ParseToken( p );
+ strcpy( m_szTypedefBaseClass, com_token );
+ }
+ }
+
+ if ( !wascomma )
+ break;
+
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ // Remove length specifiers
+ if ( !stricmp( com_token, ":" ) )
+ {
+ input = CC_ParseToken( input );
+ input = CC_ParseToken( input );
+ }
+
+ if ( !stricmp( com_token, "," ) )
+ {
+ input = CC_ParseToken( input );
+ }
+
+ if ( !stricmp( com_token, ";" ) )
+ break;
+
+ strcpy( var.m_pName, com_token );
+
+ } while ( 1 );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Parses a nested class definition
+//-----------------------------------------------------------------------------
+bool CClass::ParseNestedClass( char *&input )
+{
+ if ( stricmp( com_token, "struct" ) && stricmp( com_token, "class" ) )
+ return false;
+
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) > 0 )
+ {
+ //vprint( depth, "class %s\n", com_token );
+ char decorated[ 256 ];
+ sprintf( decorated, "%s::%s", m_szName, com_token );
+
+ CClass *cl = processor->AddClass( decorated );
+
+ // Now see if there's a base class
+ input = CC_ParseToken( input );
+ if ( !stricmp( com_token, ":" ) )
+ {
+ // Parse out public and then classname an
+ input = CC_ParseToken( input );
+ if ( !stricmp( com_token, "public" ) )
+ {
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) > 0 )
+ {
+ cl->SetBaseClass( com_token );
+
+ do
+ {
+ input = CC_ParseToken( input );
+ } while ( strlen( com_token ) && stricmp( com_token, "{" ) );
+
+ if ( !stricmp( com_token, "{" ) )
+ {
+ input = cl->ParseClassDeclaration( input );
+ }
+ }
+ }
+ }
+ else if ( !stricmp( com_token, "{" ) )
+ {
+ input = cl->ParseClassDeclaration( input );
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Parses public/protected/private
+//-----------------------------------------------------------------------------
+bool CClass::ParseProtection( char *&input, int &protection )
+{
+ if ( !stricmp( com_token, "public" ) )
+ {
+ protection = 0;
+ input = CC_ParseToken( input );
+ Assert( !stricmp( com_token, ":" ) );
+ return true;
+ }
+ else if ( !stricmp( com_token, "protected" ) )
+ {
+ protection = 1;
+ input = CC_ParseToken( input );
+ Assert( !stricmp( com_token, ":" ) );
+ return true;
+ }
+ else if ( !stricmp( com_token, "private" ) )
+ {
+ protection = 2;
+ input = CC_ParseToken( input );
+ Assert( !stricmp( com_token, ":" ) );
+ return true;
+ }
+
+ return false;
+}
+
+
+// parse until } found
+// public:, private:, protected: set protection mode, private is initial default
+// if token is not one of those, then parse and concatenate all tokens up to the first
+// ; or (
+//
+
+char *CClass::ParseClassDeclaration( char *input )
+{
+ int nestcount = 1;
+
+ // public = 0, protected = 1, private = 2;
+ int protection = 2;
+
+ do
+ {
+ input = CC_ParseToken( input );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ if ( com_token[ 1 ] == 0 )
+ {
+ if ( com_token[ 0 ] == '{' )
+ {
+ nestcount++;
+ }
+ else if ( com_token[ 0 ] == '}' )
+ {
+ nestcount--;
+ }
+ }
+
+ if ( ParseProtection( input, protection ) )
+ continue;
+
+ if ( !stricmp( com_token, ";" ) )
+ continue;
+
+ if ( com_token[0] == '#' )
+ {
+ // swallow rest of line
+ input = CC_ParseUntilEndOfLine( input );
+ continue;
+ }
+
+ if ( ParseNestedClass( input ) )
+ continue;
+
+ if ( nestcount == 1 )
+ {
+ // See if we found a line that describes the base class
+ if ( ParseBaseClass( input ) )
+ continue;
+
+ ParseClassMember( input, protection );
+ }
+
+ } while ( nestcount != 0 && ( strlen( com_token ) >= 0 ) );
+
+ return input;
+}
+
+static bool ShouldHungarianCheck( char const *name )
+{
+ if ( !Q_strncmp( name, "m_", 2 ) ||
+ !Q_strncmp( name, "g_", 2 ) ||
+ !Q_strncmp( name, "s_", 2 ) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+enum Required
+{
+ NEVER = 0,
+ ALWAYS
+};
+
+struct Impermissible
+{
+ char const *prefix;
+ char const *mustinclude;
+ int required; // if true, then must match to be permitted
+};
+
+static Impermissible g_Permissibles[] =
+{
+ { "fl", "float", ALWAYS },
+ { "b", "bool", ALWAYS },
+ { "n", "int", ALWAYS },
+ { "isz", "string_t", ALWAYS },
+ { "i", "float", NEVER },
+ { "i", "bool", NEVER },
+ { "i", "short", NEVER },
+ { "i", "long", NEVER },
+ { "ui", "int", ALWAYS },
+ { "sz", "char", ALWAYS },
+ { "ch", "char", ALWAYS },
+ { "uch", "float", NEVER },
+ { "uch", "int", NEVER },
+ { "uch", "short", NEVER },
+ { "uch", "long", NEVER },
+ { "s", "short", ALWAYS },
+ { "us", "short", ALWAYS },
+ { "l", "long", ALWAYS },
+ { "ul", "long", ALWAYS },
+// { "f", "int", NEVER },
+// { "f", "short", NEVER },
+// { "f", "int", NEVER },
+ { "a", "UtlVector", ALWAYS },
+ { "h", "handle", ALWAYS },
+ { "p", "*", ALWAYS },
+};
+
+void CClass::CheckForHungarianErrors( int& warnings )
+{
+ int testcount = sizeof( g_Permissibles ) / sizeof( g_Permissibles[ 0 ] );
+
+ for ( int i = 0; i < m_nVarCount; i++ )
+ {
+ CClassVariable *var = m_Variables[ i ];
+
+ // Only check m_, s_, and g_ variables for now
+ if ( !ShouldHungarianCheck( var->m_szName ) )
+ {
+ continue;
+ }
+
+ bool isstatic = false;
+ char *p = var->m_szType;
+ while ( 1 )
+ {
+ p = CC_ParseToken( p );
+ if ( strlen( com_token ) <= 0 )
+ break;
+ if ( !stricmp( com_token, "static" ) )
+ {
+ isstatic = true;
+ break;
+ }
+ }
+
+ // Check for errors
+ for ( int j = 0; j < testcount; ++j )
+ {
+ Impermissible *tst = &g_Permissibles[ j ];
+
+ bool match = !Q_strncmp( var->m_szName + 2, tst->prefix, Q_strlen( tst->prefix ) ) ? true : false;
+ if ( !match )
+ continue;
+
+ // The first character after the prefix must be upper case or we skip...
+ int nextchar = 2 + Q_strlen( tst->prefix );
+
+ if ( !isupper( var->m_szName[ nextchar ] ) )
+ continue;
+
+ bool typeFound = Q_stristr( var->m_szType, tst->mustinclude ) ? true : false;
+
+ switch ( tst->required )
+ {
+ default:
+ case ALWAYS:
+ {
+ if ( !typeFound )
+ {
+ vprint( 1, "%s might have wrong type %s\n", var->m_szName, var->m_szType );
+ ++warnings;
+ }
+ else
+ {
+ return;
+ }
+ }
+ break;
+ case NEVER:
+ {
+ if ( typeFound )
+ {
+ vprint( 1, "%s might have wrong type %s\n", var->m_szName, var->m_szType );
+ ++warnings;
+ }
+ else
+ {
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+
+ if ( !Q_strncmp( var->m_szName, "m_f", 3 ) &&
+ Q_strncmp( var->m_szName, "m_fl", 4 ) && isupper( var->m_szName[3] ) )
+ {
+ // If it's a "flag" and not a "float" type, it better be a bool or an int
+ if ( !Q_stristr( var->m_szType, "bool" ) &&
+ !Q_strstr( var->m_szType, "int" ) )
+ {
+ vprint( 1, "%s might have wrong type %s\n", var->m_szName, var->m_szType );
+ ++warnings;
+ return;
+ }
+ }
+ }
+
+}