Team Fortress 2 Source Code as on 22/4/2020
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.

1581 lines
33 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <assert.h>
  8. #include "stdafx.h"
  9. #include <stdio.h>
  10. #include <windows.h>
  11. #include "classcheck_util.h"
  12. #include "class.h"
  13. #include "icodeprocessor.h"
  14. CClass::CClass( const char *name )
  15. {
  16. m_nVarCount = 0;
  17. m_nMemberCount = 0;
  18. m_nTDCount = 0;
  19. m_nPredTDCount = 0;
  20. strcpy( m_szName, name );
  21. m_szBaseClass[0]=0;
  22. m_pBaseClass = NULL;
  23. m_szTypedefBaseClass[0]=0;
  24. m_bDerivedFromCBaseEntity = false;
  25. m_bHasSaveRestoreData = false;
  26. m_bHasPredictionData = false;
  27. m_bConstructPredictableCalled = false;
  28. m_bHasRecvTableData = false;
  29. m_nClassDataSize = 0;
  30. }
  31. CClass::~CClass( void )
  32. {
  33. int i;
  34. for ( i = 0; i < m_nVarCount; i++ )
  35. {
  36. delete m_Variables[ i ];
  37. }
  38. m_nVarCount = 0;
  39. for ( i = 0; i < m_nMemberCount; i++ )
  40. {
  41. delete m_Members[ i ];
  42. }
  43. m_nMemberCount = 0;
  44. for ( i = 0; i < m_nTDCount; i++ )
  45. {
  46. delete m_TDFields[ i ];
  47. }
  48. m_nTDCount = 0;
  49. for ( i = 0; i < m_nPredTDCount; i++ )
  50. {
  51. delete m_PredTDFields[ i ];
  52. }
  53. m_nPredTDCount = 0;
  54. }
  55. CTypeDescriptionField *CClass::FindTD( const char *name )
  56. {
  57. for ( int i = 0; i < m_nTDCount; i++ )
  58. {
  59. if ( !strcmp( m_TDFields[ i ]->m_szVariableName, name ) )
  60. return m_TDFields[ i ];
  61. }
  62. return NULL;
  63. }
  64. CTypeDescriptionField *CClass::FindPredTD( const char *name )
  65. {
  66. for ( int i = 0; i < m_nPredTDCount; i++ )
  67. {
  68. if ( !strcmp( m_PredTDFields[ i ]->m_szVariableName, name ) )
  69. return m_PredTDFields[ i ];
  70. }
  71. return NULL;
  72. }
  73. CClassVariable *CClass::FindVar( const char *name, bool checkbaseclasses /*= false*/ )
  74. {
  75. CClass *cl = this;
  76. while ( cl )
  77. {
  78. for ( int i = 0; i < cl->m_nVarCount; i++ )
  79. {
  80. if ( !strcmp( cl->m_Variables[ i ]->m_szName, name ) )
  81. return cl->m_Variables[ i ];
  82. }
  83. if ( !checkbaseclasses )
  84. break;
  85. if ( !cl->m_pBaseClass )
  86. {
  87. cl->m_pBaseClass = processor->FindClass( cl->m_szBaseClass );
  88. }
  89. cl = cl->m_pBaseClass;
  90. if ( !cl )
  91. break;
  92. }
  93. return NULL;
  94. }
  95. CClassMemberFunction *CClass::FindMember( const char *name )
  96. {
  97. for ( int i = 0; i < m_nMemberCount; i++ )
  98. {
  99. if ( !strcmp( m_Members[ i ]->m_szName, name ) )
  100. return m_Members[ i ];
  101. }
  102. return NULL;
  103. }
  104. CTypeDescriptionField *CClass::AddTD( const char *name, const char *type, const char *definetype, bool incomments )
  105. {
  106. CTypeDescriptionField *td = FindTD( name );
  107. if ( !td )
  108. {
  109. td = new CTypeDescriptionField();
  110. strcpy( td->m_szVariableName, name );
  111. strcpy( td->m_szType, type );
  112. strcpy( td->m_szDefineType, definetype );
  113. td->m_bCommentedOut = incomments;
  114. m_TDFields[ m_nTDCount++ ] = td;
  115. if ( m_nTDCount >= MAX_TDFIELDS )
  116. {
  117. vprint( 0, "too many typedescription fields\n" );
  118. exit( 1 );
  119. }
  120. }
  121. return td;
  122. }
  123. CTypeDescriptionField *CClass::AddPredTD( const char *name, const char *type, const char *definetype, bool incomments, bool inrecvtable )
  124. {
  125. CTypeDescriptionField *td = FindPredTD( name );
  126. if ( !td )
  127. {
  128. td = new CTypeDescriptionField();
  129. strcpy( td->m_szVariableName, name );
  130. strcpy( td->m_szType, type );
  131. strcpy( td->m_szDefineType, definetype );
  132. td->m_bCommentedOut = incomments;
  133. td->m_bRepresentedInRecvTable = inrecvtable;
  134. m_PredTDFields[ m_nPredTDCount++ ] = td;
  135. if ( m_nPredTDCount >= MAX_TDFIELDS )
  136. {
  137. vprint( 0, "too many prediction typedescription fields\n" );
  138. exit( 1 );
  139. }
  140. }
  141. return td;
  142. }
  143. CClassVariable *CClass::AddVar( const char *name )
  144. {
  145. CClassVariable *var = FindVar( name );
  146. if ( !var )
  147. {
  148. var = new CClassVariable();
  149. strcpy( var->m_szName, name );
  150. m_Variables[ m_nVarCount++ ] = var;
  151. if ( m_nVarCount >= MAX_VARIABLES )
  152. {
  153. vprint( 0, "too many variables\n" );
  154. exit( 1 );
  155. }
  156. }
  157. return var;
  158. }
  159. CClassMemberFunction *CClass::AddMember( const char *name )
  160. {
  161. CClassMemberFunction *member = FindMember( name );
  162. if ( !member )
  163. {
  164. member = new CClassMemberFunction();
  165. strcpy( member->m_szName, name );
  166. m_Members[ m_nMemberCount++ ] = member;
  167. if ( m_nMemberCount >= MAX_MEMBERS )
  168. {
  169. vprint( 0, "too many members\n" );
  170. exit( 1 );
  171. }
  172. }
  173. return member;
  174. }
  175. void CClass::SetBaseClass( const char *name )
  176. {
  177. if ( !m_szBaseClass[ 0 ] )
  178. {
  179. strcpy( m_szBaseClass, name );
  180. }
  181. else if ( stricmp( m_szBaseClass, name ) )
  182. {
  183. vprint( 0, "Base class differs for %s %s vs %s\n", m_szName, m_szBaseClass, name );
  184. }
  185. }
  186. void CClass::CheckChildOfBaseEntity( const char *baseentityclass )
  187. {
  188. m_bDerivedFromCBaseEntity = false;
  189. if ( !stricmp( m_szName, baseentityclass ) )
  190. {
  191. m_bDerivedFromCBaseEntity = true;
  192. return;
  193. }
  194. CClass *base = m_pBaseClass;
  195. while ( base )
  196. {
  197. // Early out?
  198. if ( base->m_bDerivedFromCBaseEntity )
  199. {
  200. m_bDerivedFromCBaseEntity = true;
  201. return;
  202. }
  203. // Check name
  204. if ( !stricmp( base->m_szName, baseentityclass ) )
  205. {
  206. m_bDerivedFromCBaseEntity = true;
  207. return;
  208. }
  209. // Keep going up hierarchy
  210. base = base->m_pBaseClass;
  211. }
  212. }
  213. static bool IsType( char *input, char *test )
  214. {
  215. char *pMatch = strstr( input, test );
  216. if ( !pMatch )
  217. return false;
  218. size_t nLen = strlen(test);
  219. if ( ( pMatch[nLen] != 0 ) && (pMatch[nLen] != ' ') )
  220. return false;
  221. if ( input != pMatch && (*(pMatch-1) != ' ') )
  222. return false;
  223. return true;
  224. }
  225. static char const *TranslateSimpleType( CClassVariable *var )
  226. {
  227. static char out[ 256 ];
  228. out[ 0 ] = 0;
  229. char *input = var->m_szType;
  230. // Don't know how to handle templatized things yet
  231. if ( strstr( input, "<" ) )
  232. {
  233. return out;
  234. }
  235. if ( IsType( input, "bool" ) )
  236. {
  237. return "FIELD_BOOLEAN";
  238. }
  239. else if ( IsType( input, "short" ) )
  240. {
  241. return "FIELD_SHORT";
  242. }
  243. else if ( IsType( input, "int" ) )
  244. {
  245. return "FIELD_INTEGER";
  246. }
  247. else if ( IsType( input, "byte" ) )
  248. {
  249. return "FIELD_CHARACTER";
  250. }
  251. else if ( IsType( input, "float" ) )
  252. {
  253. return "FIELD_FLOAT";
  254. }
  255. else if ( IsType( input, "EHANDLE" ) || IsType( input, "CHandle" ) )
  256. {
  257. return "FIELD_EHANDLE";
  258. }
  259. else if ( IsType( input, "color32" ) )
  260. {
  261. return "FIELD_COLOR32";
  262. }
  263. else if ( IsType( input, "Vector" ) || IsType( input, "QAngle" ) )
  264. {
  265. return "FIELD_VECTOR";
  266. }
  267. else if ( IsType( input, "Quaternion" ) )
  268. {
  269. return "FIELD_QUATERNION";
  270. }
  271. else if ( IsType( input, "VMatrix" ) )
  272. {
  273. return "FIELD_VMATRIX";
  274. }
  275. else if ( IsType( input, "string_t" ) )
  276. {
  277. return "FIELD_STRING";
  278. }
  279. else if ( IsType( input, "char" ) )
  280. {
  281. return "FIELD_CHARACTER";
  282. }
  283. return out;
  284. }
  285. void CClass::ReportTypeMismatches( CClassVariable *var, CTypeDescriptionField *td )
  286. {
  287. char const *t = TranslateSimpleType( var );
  288. if ( !t[0] )
  289. return;
  290. // Special cases
  291. if ( td->m_bCommentedOut )
  292. return;
  293. if ( !strcmp( td->m_szType, "FIELD_TIME" ) )
  294. {
  295. if ( !strcmp( t, "FIELD_FLOAT" ) )
  296. return;
  297. }
  298. if ( !strcmp( td->m_szType, "FIELD_TICK" ) )
  299. {
  300. if ( !strcmp( t, "FIELD_INTEGER" ) )
  301. return;
  302. }
  303. if ( !strcmp( td->m_szType, "FIELD_MODELNAME" ) || !strcmp( td->m_szType, "FIELD_SOUNDNAME" ) )
  304. {
  305. if ( !strcmp( t, "FIELD_STRING" ) )
  306. return;
  307. }
  308. if ( !strcmp( td->m_szType, "FIELD_MODELINDEX" ) || !strcmp( td->m_szType, "FIELD_MATERIALINDEX" ) )
  309. {
  310. if ( !strcmp( t, "FIELD_INTEGER" ) )
  311. return;
  312. }
  313. if ( !strcmp( td->m_szType, "FIELD_POSITION_VECTOR" ) )
  314. {
  315. if ( !strcmp( t, "FIELD_VECTOR" ) )
  316. return;
  317. }
  318. if ( !strcmp( td->m_szType, "FIELD_VMATRIX_WORLDSPACE" ) )
  319. {
  320. if ( !strcmp( t, "FIELD_VMATRIX" ) )
  321. return;
  322. }
  323. if ( strcmp( t, td->m_szType ) )
  324. {
  325. vprint( 0, "class %s has an incorrect FIELD_ type for variable '%s (%s, %s)'\n",
  326. m_szName, var->m_szName, var->m_szType, td->m_szType );
  327. }
  328. }
  329. bool CClass::CheckForMissingTypeDescriptionFields( int& missingcount, bool createtds )
  330. {
  331. bool bret = false;
  332. missingcount = 0;
  333. // Didn't specify a TYPEDESCRIPTION at all
  334. if ( !m_bHasSaveRestoreData )
  335. return bret;
  336. for ( int i = 0; i < m_nVarCount; i++ )
  337. {
  338. CClassVariable *var = m_Variables[ i ];
  339. bool isstatic = false;
  340. char *p = var->m_szType;
  341. while ( 1 )
  342. {
  343. p = CC_ParseToken( p );
  344. if ( strlen( com_token ) <= 0 )
  345. break;
  346. if ( !stricmp( com_token, "static" ) )
  347. {
  348. isstatic = true;
  349. break;
  350. }
  351. }
  352. // Statics aren't encoded
  353. if ( isstatic )
  354. continue;
  355. char *goodname = var->m_szName;
  356. // Skip * pointer modifier
  357. while ( *goodname && *goodname == '*' )
  358. {
  359. goodname++;
  360. }
  361. CTypeDescriptionField *td = FindTD( goodname );
  362. if ( td )
  363. {
  364. ReportTypeMismatches( var, td );
  365. continue;
  366. }
  367. bret = true;
  368. missingcount++;
  369. if ( !createtds )
  370. {
  371. vprint( 0, "class %s missing typedescription_t field for variable '%s %s'\n",
  372. m_szName, var->m_szType, var->m_szName );
  373. continue;
  374. }
  375. char const *t = TranslateSimpleType( var );
  376. vprint( 0, "//\tClass %s:\n", m_szName );
  377. if ( var->m_bIsArray &&
  378. (
  379. stricmp( var->m_szType, "char" ) ||
  380. stricmp( t, "FIELD_STRING" )
  381. ) )
  382. {
  383. if ( *t )
  384. {
  385. vprint( 0, "\tDEFINE_ARRAY( %s, %s, %s ),\n", goodname, t, var->m_szArraySize );
  386. }
  387. else
  388. {
  389. vprint( 0, "\t// DEFINE_ARRAY( %s, %s, %s ),\n", goodname, var->m_szType, var->m_szArraySize );
  390. }
  391. }
  392. else
  393. {
  394. if ( *t )
  395. {
  396. vprint( 0, "\tDEFINE_FIELD( %s, %s ),\n", goodname, t );
  397. }
  398. else
  399. {
  400. vprint( 0, "\t// DEFINE_FIELD( %s, %s ),\n", goodname, var->m_szType );
  401. }
  402. }
  403. }
  404. return bret;
  405. }
  406. bool CClass::CheckForPredictionFieldsInRecvTableNotMarkedAsSuchCorrectly( int &missingcount )
  407. {
  408. bool bret = false;
  409. missingcount = 0;
  410. // Didn't specify a TYPEDESCRIPTION at all
  411. if ( !m_bHasPredictionData )
  412. return bret;
  413. if ( !m_bHasRecvTableData )
  414. return bret;
  415. for ( int i = 0; i < m_nVarCount; i++ )
  416. {
  417. CClassVariable *var = m_Variables[ i ];
  418. bool inreceivetable = var->m_bInRecvTable;
  419. bool isstatic = false;
  420. char *p = var->m_szType;
  421. while ( 1 )
  422. {
  423. p = CC_ParseToken( p );
  424. if ( strlen( com_token ) <= 0 )
  425. break;
  426. if ( !stricmp( com_token, "static" ) )
  427. {
  428. isstatic = true;
  429. break;
  430. }
  431. }
  432. // Statics aren't encoded
  433. if ( isstatic )
  434. continue;
  435. char *goodname = var->m_szName;
  436. // Skip * pointer modifier
  437. while ( *goodname && *goodname == '*' )
  438. goodname++;
  439. CTypeDescriptionField *td = FindPredTD( goodname );
  440. // Missing variables are caught in a different routine
  441. td = FindPredTD( goodname );
  442. if ( !td )
  443. continue;
  444. // These are implicitly ok
  445. if ( !strcmp( td->m_szDefineType, "DEFINE_PRED_TYPEDESCRIPTION" ) )
  446. {
  447. CClass *cl2 = processor->FindClass( td->m_szType );
  448. if ( cl2 )
  449. {
  450. bret = cl2->CheckForPredictionFieldsInRecvTableNotMarkedAsSuchCorrectly( missingcount );
  451. }
  452. continue;
  453. }
  454. // Looks good (either in or out!)
  455. // Check for appripriate flags
  456. if ( inreceivetable == td->m_bRepresentedInRecvTable )
  457. continue;
  458. bret = true;
  459. missingcount++;
  460. if ( inreceivetable && !td->m_bRepresentedInRecvTable )
  461. {
  462. vprint( 0, "%s::%s: Missing FTYPEDESC_INSENDTABLE flag in prediction typedescription\n", m_szName, var->m_szName );
  463. }
  464. else
  465. {
  466. vprint( 0, "%s::%s: Field marked as FTYPEDESC_INSENDTABLE in prediction typedescription missing from RecvTable\n", m_szName, var->m_szName );
  467. }
  468. }
  469. return bret;
  470. }
  471. bool CClass::CheckForMissingPredictionFields( int& missingcount, bool createtds )
  472. {
  473. bool bret = false;
  474. missingcount = 0;
  475. // Didn't specify a TYPEDESCRIPTION at all
  476. if ( !m_bHasPredictionData )
  477. return bret;
  478. for ( int i = 0; i < m_nVarCount; i++ )
  479. {
  480. CClassVariable *var = m_Variables[ i ];
  481. // private and protected variables can't be referenced in data tables right now
  482. //if ( var->m_Type != CClassVariable::TPUBLIC )
  483. // continue;
  484. bool isstatic = false;
  485. char *p = var->m_szType;
  486. while ( 1 )
  487. {
  488. p = CC_ParseToken( p );
  489. if ( strlen( com_token ) <= 0 )
  490. break;
  491. if ( !stricmp( com_token, "static" ) )
  492. {
  493. isstatic = true;
  494. break;
  495. }
  496. }
  497. // Statics aren't encoded
  498. if ( !isstatic )
  499. {
  500. char *goodname = var->m_szName;
  501. // Skip * pointer modifier
  502. while ( *goodname && *goodname == '*' )
  503. goodname++;
  504. CTypeDescriptionField *td = FindPredTD( goodname );
  505. td = FindPredTD( goodname );
  506. if ( !td )
  507. {
  508. bret = true;
  509. missingcount++;
  510. if ( !createtds )
  511. {
  512. vprint( 0, "class %s missing prediction typedescription_t field for variable '%s %s'\n",
  513. m_szName, var->m_szType, var->m_szName );
  514. }
  515. else
  516. {
  517. char const *t = TranslateSimpleType( var );
  518. vprint( 0, "//\tClass %s:\n", m_szName );
  519. if ( var->m_bIsArray &&
  520. (
  521. stricmp( var->m_szType, "char" ) ||
  522. stricmp( t, "FIELD_STRING" )
  523. ) )
  524. {
  525. if ( *t )
  526. {
  527. vprint( 0, "\tDEFINE_ARRAY( %s, %s, %s ),\n", goodname, t, var->m_szArraySize );
  528. }
  529. else
  530. {
  531. vprint( 0, "\t// DEFINE_ARRAY( %s, %s, %s ),\n", goodname, var->m_szType, var->m_szArraySize );
  532. }
  533. }
  534. else
  535. {
  536. if ( *t )
  537. {
  538. vprint( 0, "\tDEFINE_FIELD( %s, %s ),\n", goodname, t );
  539. }
  540. else
  541. {
  542. vprint( 0, "\t// DEFINE_FIELD( %s, %s ),\n", goodname, var->m_szType );
  543. }
  544. }
  545. }
  546. }
  547. }
  548. }
  549. return bret;
  550. }
  551. void AppendType( const char *token, char *type )
  552. {
  553. strcat( type, token );
  554. strcat( type, " " );
  555. }
  556. class MissingType
  557. {
  558. public:
  559. CClass *owning_class;
  560. CClassVariable *var;
  561. };
  562. #include "utldict.h"
  563. CUtlDict< MissingType, unsigned short > missing_types;
  564. bool IsMissingType( CClass *cl, CClassVariable *var )
  565. {
  566. unsigned short lookup;
  567. lookup = missing_types.Find( var->m_szType );
  568. if ( lookup != missing_types.InvalidIndex() )
  569. return true;
  570. MissingType t;
  571. t.owning_class = cl;
  572. t.var = var;
  573. missing_types.Insert( var->m_szType, t );
  574. return true;
  575. }
  576. void ReportMissingTypes( void )
  577. {
  578. int c = missing_types.Count();
  579. for ( int i= 0; i < c; i++ )
  580. {
  581. MissingType *t = &missing_types[ i ];
  582. if ( !t )
  583. continue;
  584. if ( !t->owning_class )
  585. continue;
  586. if ( !t->owning_class->m_bDerivedFromCBaseEntity )
  587. continue;
  588. if ( !t->var )
  589. continue;
  590. vprint( 0, "Can't compute size of %s %s %s\n",
  591. t->owning_class->m_szName, t->var->m_szType, t->var->m_szName );
  592. }
  593. }
  594. void ClearMissingTypes()
  595. {
  596. missing_types.Purge();
  597. }
  598. static int GetTypeSize( CClass *cl, CClassVariable *var )
  599. {
  600. int out = 0;
  601. char *input = var->m_szType;
  602. // Don't know how to handle templatized things yet
  603. if ( strstr( input, "<" ) )
  604. {
  605. IsMissingType( cl, var );
  606. return out;
  607. }
  608. if ( strstr( var->m_szName, "*" ) )
  609. {
  610. return sizeof( void * );
  611. }
  612. if ( strstr( input, "bool" ) )
  613. {
  614. return sizeof( bool );
  615. }
  616. else if ( strstr( input, "int64" ) )
  617. {
  618. return sizeof( __int64 );
  619. }
  620. else if ( strstr( input, "short" ) )
  621. {
  622. return sizeof( short );
  623. }
  624. else if ( strstr( input, "unsigned short" ) )
  625. {
  626. return sizeof( unsigned short );
  627. }
  628. else if ( strstr( input, "int" ) )
  629. {
  630. return sizeof( int );
  631. }
  632. else if ( strstr( input, "float" ) )
  633. {
  634. return sizeof( float );
  635. }
  636. else if ( strstr( input, "vec_t" ) )
  637. {
  638. return sizeof( float );
  639. }
  640. else if ( strstr( input, "Vector" ) || strstr( input, "QAngle" ) )
  641. {
  642. return 3 * sizeof( float );
  643. }
  644. else if ( strstr( input, "vec3_t" ) )
  645. {
  646. return 3 * sizeof( float );
  647. }
  648. else if ( strstr( input, "char" ) )
  649. {
  650. return sizeof( char );
  651. }
  652. else if ( strstr( input, "unsigned char" ) )
  653. {
  654. return sizeof( unsigned char );
  655. }
  656. else if ( strstr( input, "BYTE" ) )
  657. {
  658. return sizeof( char );
  659. }
  660. else if ( strstr( input, "byte" ) )
  661. {
  662. return sizeof( char );
  663. }
  664. else if ( !strcmp( input, "unsigned" ) )
  665. {
  666. return sizeof(unsigned int);
  667. }
  668. else if ( strstr( input, "long" ) )
  669. {
  670. return sizeof( int );
  671. }
  672. else if ( strstr( input, "color32" ) )
  673. {
  674. return sizeof( int );
  675. }
  676. // It's a pointer
  677. else if ( strstr( input, "*" ) )
  678. {
  679. return sizeof( void * );
  680. }
  681. // Static data doesn't count
  682. else if ( strstr( input, "static" ) )
  683. {
  684. return 0;
  685. }
  686. // Okay, see if it's a classname
  687. CClass *base = processor->FindClass( input );
  688. if ( base )
  689. {
  690. return base->m_nClassDataSize;
  691. }
  692. IsMissingType( cl, var );
  693. return out;
  694. }
  695. void CClass::AddVariable( int protection, char *type, char *name, bool array, char *arraysize )
  696. {
  697. CClassVariable *var = AddVar( name );
  698. if ( !var )
  699. return;
  700. strcpy( var->m_szType, type );
  701. var->m_Type = (CClassVariable::VARTYPE)protection;
  702. var->m_TypeSize = GetTypeSize( this, var );
  703. m_nClassDataSize += var->m_TypeSize;
  704. if ( array )
  705. {
  706. var->m_bIsArray = true;
  707. strcpy( var->m_szArraySize, arraysize );
  708. }
  709. else
  710. {
  711. var->m_bIsArray = false;
  712. }
  713. }
  714. //-----------------------------------------------------------------------------
  715. // Parses information to determine the base class of this class
  716. //-----------------------------------------------------------------------------
  717. bool CClass::ParseBaseClass( char *&input )
  718. {
  719. if ( !strcmp( com_token, "DECLARE_CLASS" )
  720. || !strcmp( com_token, "DECLARE_CLASS_GAMEROOT" )
  721. || !strcmp( com_token, "DECLARE_CLASS_NOFRIEND" ) )
  722. {
  723. input = CC_ParseToken( input );
  724. Assert( !strcmp( com_token, "(") );
  725. input = CC_ParseToken( input );
  726. do
  727. {
  728. input = CC_ParseToken( input );
  729. } while( strcmp( com_token, ",") );
  730. m_szTypedefBaseClass[0] = 0;
  731. input = CC_ParseToken( input );
  732. do
  733. {
  734. strcat( m_szTypedefBaseClass, com_token );
  735. input = CC_ParseToken( input );
  736. } while( strcmp( com_token, ")") );
  737. return true;
  738. }
  739. else if ( !strcmp( com_token, "DECLARE_CLASS_NOBASE" ) )
  740. {
  741. input = CC_ParseToken( input );
  742. Assert( !strcmp( com_token, "(") );
  743. input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
  744. return true;
  745. }
  746. return false;
  747. }
  748. //-----------------------------------------------------------------------------
  749. // Parses networkvars
  750. //-----------------------------------------------------------------------------
  751. bool CClass::ParseNetworkVar( char *&input, int protection )
  752. {
  753. MemberVarParse_t var;
  754. if ( !strcmp( com_token, "CNetworkVar" ) ||
  755. !strcmp( com_token, "CNetworkVarForDerived" ) ||
  756. !strcmp( com_token, "CNetworkVarEmbedded" ) )
  757. {
  758. input = CC_ParseToken( input );
  759. Assert( !strcmp( com_token, "(") );
  760. input = CC_ParseToken( input );
  761. do
  762. {
  763. strcat( var.m_pType, com_token );
  764. strcat( var.m_pType, " " );
  765. input = CC_ParseToken( input );
  766. } while( strcmp( com_token, ",") );
  767. input = CC_ParseToken( input );
  768. do
  769. {
  770. strcat( var.m_pName, com_token );
  771. input = CC_ParseToken( input );
  772. } while( strcmp( com_token, ")") );
  773. AddVariable( protection, var.m_pType, var.m_pName, false );
  774. return true;
  775. }
  776. if ( !strcmp( com_token, "CNetworkHandle" ) || !strcmp( com_token, "CNetworkHandleForDerived" ) )
  777. {
  778. input = CC_ParseToken( input );
  779. Assert( !strcmp( com_token, "(") );
  780. input = CC_ParseToken( input );
  781. strcpy( var.m_pType, "CHandle<" );
  782. do
  783. {
  784. strcat( var.m_pType, com_token );
  785. strcat( var.m_pType, " " );
  786. input = CC_ParseToken( input );
  787. } while( strcmp( com_token, ",") );
  788. strcat( var.m_pType, ">" );
  789. input = CC_ParseToken( input );
  790. do
  791. {
  792. strcat( var.m_pName, com_token );
  793. input = CC_ParseToken( input );
  794. } while( strcmp( com_token, ")") );
  795. AddVariable( protection, "EHANDLE", var.m_pName, false );
  796. return true;
  797. }
  798. if ( !strcmp( com_token, "CNetworkVector" ) ||
  799. !strcmp( com_token, "CNetworkVectorForDerived" ) ||
  800. !strcmp( com_token, "CNetworkQAngle" ) )
  801. {
  802. input = CC_ParseToken( input );
  803. Assert( !strcmp( com_token, "(") );
  804. input = CC_ParseToken( input );
  805. do
  806. {
  807. strcat( var.m_pName, com_token );
  808. input = CC_ParseToken( input );
  809. } while( strcmp( com_token, ")") );
  810. AddVariable( protection, "Vector", var.m_pName, false );
  811. return true;
  812. }
  813. if ( !strcmp( com_token, "CNetworkColor32" ) )
  814. {
  815. input = CC_ParseToken( input );
  816. Assert( !strcmp( com_token, "(") );
  817. input = CC_ParseToken( input );
  818. do
  819. {
  820. strcat( var.m_pName, com_token );
  821. input = CC_ParseToken( input );
  822. } while( strcmp( com_token, ")") );
  823. AddVariable( protection, "color32", var.m_pName, false );
  824. return true;
  825. }
  826. if ( !strcmp( com_token, "CNetworkString" ) )
  827. {
  828. input = CC_ParseToken( input );
  829. Assert( !strcmp( com_token, "(") );
  830. input = CC_ParseToken( input );
  831. do
  832. {
  833. strcat( var.m_pName, com_token );
  834. input = CC_ParseToken( input );
  835. } while( strcmp( com_token, ",") );
  836. input = CC_ParseToken( input );
  837. do
  838. {
  839. strcat( var.m_pArraySize, com_token );
  840. input = CC_ParseToken( input );
  841. } while( strcmp( com_token, ")") );
  842. AddVariable( protection, "char *", var.m_pName, true, var.m_pArraySize );
  843. return true;
  844. }
  845. if ( !strcmp( com_token, "CNetworkArray" ) || !strcmp( com_token, "CNetworkArrayForDerived" ) )
  846. {
  847. input = CC_ParseToken( input );
  848. Assert( !strcmp( com_token, "(") );
  849. input = CC_ParseToken( input );
  850. do
  851. {
  852. strcat( var.m_pType, com_token );
  853. strcat( var.m_pType, " " );
  854. input = CC_ParseToken( input );
  855. } while( strcmp( com_token, ",") );
  856. input = CC_ParseToken( input );
  857. do
  858. {
  859. strcat( var.m_pName, com_token );
  860. input = CC_ParseToken( input );
  861. } while( strcmp( com_token, ",") );
  862. input = CC_ParseToken( input );
  863. do
  864. {
  865. strcat( var.m_pArraySize, com_token );
  866. input = CC_ParseToken( input );
  867. } while( strcmp( com_token, ")") );
  868. AddVariable( protection, var.m_pType, var.m_pName, true, var.m_pArraySize );
  869. return true;
  870. }
  871. return false;
  872. }
  873. //-----------------------------------------------------------------------------
  874. // Parses a class member definition
  875. //-----------------------------------------------------------------------------
  876. bool CClass::ParseClassMember( char *&input, int protection )
  877. {
  878. MemberVarParse_t var;
  879. bool isfunction = false;
  880. bool wascomma = false;
  881. bool skipvar = false;
  882. if ( ParseNetworkVar( input, protection ) )
  883. return true;
  884. strcpy( var.m_pName, com_token );
  885. if ( !stricmp( var.m_pName, "SHARED_CLASSNAME" ) )
  886. {
  887. input = CC_ParseToken( input );
  888. if ( !stricmp( com_token, "(" ) )
  889. {
  890. char inside[ 256 ];
  891. char *saveinput = input;
  892. input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
  893. int len = input - saveinput;
  894. strncpy( inside, saveinput, len );
  895. inside[ len ] =0;
  896. strcat( var.m_pName, "(" );
  897. strcat( var.m_pName, inside );
  898. }
  899. }
  900. do
  901. {
  902. input = CC_ParseToken( input );
  903. if ( strlen( com_token ) <= 0 )
  904. break;
  905. if ( !stricmp( com_token, "(" ) )
  906. {
  907. char *saveinput = input;
  908. isfunction = true;
  909. input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
  910. // see if the function is being declared in line here
  911. input = CC_ParseToken( input );
  912. if ( !stricmp( com_token, "const" ) )
  913. {
  914. // Swallow const if we see it
  915. input = CC_ParseToken( input );
  916. }
  917. if ( !stricmp( com_token, "{" ) )
  918. {
  919. input = CC_DiscardUntilMatchingCharIncludingNesting( input, "{}" );
  920. }
  921. // pure virtual function?
  922. else if ( !stricmp( com_token, "=" ) )
  923. {
  924. char ch;
  925. input = CC_RawParseChar( input, ";", &ch );
  926. }
  927. // this was a pointer to a base function
  928. else if ( !stricmp( com_token, "(" ) )
  929. {
  930. char *end = input - 2;
  931. input = saveinput;
  932. char pfn[ 256 ];
  933. int len = end - saveinput;
  934. strncpy( pfn, input, len );
  935. pfn[ len ] = 0;
  936. do
  937. {
  938. input = CC_ParseToken( input );
  939. if ( strlen( com_token ) <= 0 )
  940. break;
  941. if ( com_token[0] == '*' )
  942. {
  943. break;
  944. }
  945. } while ( 1 );
  946. if ( com_token[0] == '*' )
  947. {
  948. // com_token is the variable name
  949. sprintf( var.m_pType, "%s (%s)", var.m_pName, pfn );
  950. strcpy( var.m_pName, com_token );
  951. input = end + 1;
  952. }
  953. if ( *input == '(' )
  954. input++;
  955. input = CC_DiscardUntilMatchingCharIncludingNesting( input, "()" );
  956. isfunction = false;
  957. }
  958. break;
  959. }
  960. else if ( !stricmp( com_token, "[" ) )
  961. {
  962. // It's an array
  963. var.m_bArray = true;
  964. char ch;
  965. char *oldinput = input;
  966. do
  967. {
  968. input = CC_RawParseChar( input, "]", &ch );
  969. if ( *input && ( *input == '[' ) )
  970. {
  971. input++;
  972. continue;
  973. }
  974. break;
  975. } while ( 1 );
  976. int len = input-oldinput - 1;
  977. if ( len > 0 )
  978. {
  979. strncpy( var.m_pArraySize, oldinput, len );
  980. }
  981. var.m_pArraySize[ len ] = 0;
  982. break;
  983. }
  984. else if ( !stricmp( com_token, ";" ) )
  985. {
  986. break;
  987. }
  988. else if ( !stricmp( com_token, ":" ) && !isfunction )
  989. {
  990. // Eliminate the length specification
  991. input = CC_ParseToken( input );
  992. continue;
  993. }
  994. else if ( !stricmp( com_token, "," ) )
  995. {
  996. wascomma = true;
  997. break;
  998. }
  999. // It's a templatized var
  1000. else if (( com_token[ strlen( com_token ) - 1 ] == '<' ) && strcmp(var.m_pName, "operator") )
  1001. {
  1002. do
  1003. {
  1004. AppendType( var.m_pName, var.m_pType );
  1005. strcpy( var.m_pName, com_token );
  1006. input = CC_ParseToken( input );
  1007. if ( strlen( com_token ) <= 0 )
  1008. break;
  1009. }
  1010. while ( strcmp( com_token, ">" ) );
  1011. AppendType( var.m_pName, var.m_pType );
  1012. strcpy( var.m_pName, com_token );
  1013. }
  1014. else
  1015. {
  1016. if ( !stricmp( var.m_pName, "typedef" ) ||
  1017. !stricmp( var.m_pName, "enum" ) ||
  1018. !stricmp( var.m_pName, "friend" ) )
  1019. {
  1020. skipvar = true;
  1021. }
  1022. AppendType( var.m_pName, var.m_pType );
  1023. strcpy( var.m_pName, com_token );
  1024. continue;
  1025. }
  1026. } while ( 1 );
  1027. if ( strlen( var.m_pType ) >= 1 )
  1028. {
  1029. var.m_pType[ strlen( var.m_pType ) - 1 ] = 0;
  1030. }
  1031. if ( var.m_pType[0]==0 &&
  1032. ( !strcmp( var.m_pName, "CUSTOM_SCHEDULES" ) ||
  1033. !strcmp( var.m_pName, "DEFINE_CUSTOM_SCHEDULE_PROVIDER" ) ||
  1034. !strcmp( var.m_pName, "DEFINE_CUSTOM_AI" ) ||
  1035. !strcmp( var.m_pName, "DECLARE_DATADESC" ) ||
  1036. !strcmp( var.m_pName, "DECLARE_EMBEDDED_DATADESC" ) ||
  1037. !strcmp( var.m_pName, "DECLARE_SERVERCLASS" ) ||
  1038. !strcmp( var.m_pName, "DECLARE_CLIENTCLASS" ) ||
  1039. !strcmp( var.m_pName, "DECLARE_ENTITY_PANEL" ) ||
  1040. !strcmp( var.m_pName, "DECLARE_MINIMAP_PANEL" ) ||
  1041. !strcmp( var.m_pName, "MANUALMODE_GETSET_PROP" ) ) )
  1042. {
  1043. return true;
  1044. }
  1045. if ( var.m_pType[0]==0 &&
  1046. ( !strcmp( var.m_pName, "DECLARE_PREDICTABLE" ) ||
  1047. !strcmp( var.m_pName, "DECLARE_EMBEDDED_PREDDESC" ) ) )
  1048. {
  1049. m_bHasPredictionData = true;
  1050. return true;
  1051. }
  1052. /*
  1053. if ( var.m_pName[0] == '*' )
  1054. {
  1055. strcat( type, " *" );
  1056. char newname[ 256 ];
  1057. strcpy( newname, &var.m_pName[1] );
  1058. strcpy( var.m_pName, newname );
  1059. }
  1060. */
  1061. if ( isfunction )
  1062. {
  1063. CClassMemberFunction *member = AddMember( var.m_pName );
  1064. if ( member )
  1065. {
  1066. strcpy( member->m_szType, var.m_pType );
  1067. member->m_Type = (CClassMemberFunction::MEMBERTYPE)protection;
  1068. }
  1069. }
  1070. else
  1071. {
  1072. // It's a variable
  1073. do
  1074. {
  1075. if ( !skipvar )
  1076. {
  1077. AddVariable( protection, var.m_pType, var.m_pName, var.m_bArray, var.m_pArraySize );
  1078. }
  1079. else if ( !stricmp( var.m_pName, "BaseClass" ) )
  1080. {
  1081. if ( !m_szTypedefBaseClass[0] )
  1082. {
  1083. char *p = var.m_pType;
  1084. p = CC_ParseToken( p );
  1085. p = CC_ParseToken( p );
  1086. strcpy( m_szTypedefBaseClass, com_token );
  1087. }
  1088. }
  1089. if ( !wascomma )
  1090. break;
  1091. input = CC_ParseToken( input );
  1092. if ( strlen( com_token ) <= 0 )
  1093. break;
  1094. // Remove length specifiers
  1095. if ( !stricmp( com_token, ":" ) )
  1096. {
  1097. input = CC_ParseToken( input );
  1098. input = CC_ParseToken( input );
  1099. }
  1100. if ( !stricmp( com_token, "," ) )
  1101. {
  1102. input = CC_ParseToken( input );
  1103. }
  1104. if ( !stricmp( com_token, ";" ) )
  1105. break;
  1106. strcpy( var.m_pName, com_token );
  1107. } while ( 1 );
  1108. }
  1109. return true;
  1110. }
  1111. //-----------------------------------------------------------------------------
  1112. // Parses a nested class definition
  1113. //-----------------------------------------------------------------------------
  1114. bool CClass::ParseNestedClass( char *&input )
  1115. {
  1116. if ( stricmp( com_token, "struct" ) && stricmp( com_token, "class" ) )
  1117. return false;
  1118. input = CC_ParseToken( input );
  1119. if ( strlen( com_token ) > 0 )
  1120. {
  1121. //vprint( depth, "class %s\n", com_token );
  1122. char decorated[ 256 ];
  1123. sprintf( decorated, "%s::%s", m_szName, com_token );
  1124. CClass *cl = processor->AddClass( decorated );
  1125. // Now see if there's a base class
  1126. input = CC_ParseToken( input );
  1127. if ( !stricmp( com_token, ":" ) )
  1128. {
  1129. // Parse out public and then classname an
  1130. input = CC_ParseToken( input );
  1131. if ( !stricmp( com_token, "public" ) )
  1132. {
  1133. input = CC_ParseToken( input );
  1134. if ( strlen( com_token ) > 0 )
  1135. {
  1136. cl->SetBaseClass( com_token );
  1137. do
  1138. {
  1139. input = CC_ParseToken( input );
  1140. } while ( strlen( com_token ) && stricmp( com_token, "{" ) );
  1141. if ( !stricmp( com_token, "{" ) )
  1142. {
  1143. input = cl->ParseClassDeclaration( input );
  1144. }
  1145. }
  1146. }
  1147. }
  1148. else if ( !stricmp( com_token, "{" ) )
  1149. {
  1150. input = cl->ParseClassDeclaration( input );
  1151. }
  1152. }
  1153. return true;
  1154. }
  1155. //-----------------------------------------------------------------------------
  1156. // Parses public/protected/private
  1157. //-----------------------------------------------------------------------------
  1158. bool CClass::ParseProtection( char *&input, int &protection )
  1159. {
  1160. if ( !stricmp( com_token, "public" ) )
  1161. {
  1162. protection = 0;
  1163. input = CC_ParseToken( input );
  1164. Assert( !stricmp( com_token, ":" ) );
  1165. return true;
  1166. }
  1167. else if ( !stricmp( com_token, "protected" ) )
  1168. {
  1169. protection = 1;
  1170. input = CC_ParseToken( input );
  1171. Assert( !stricmp( com_token, ":" ) );
  1172. return true;
  1173. }
  1174. else if ( !stricmp( com_token, "private" ) )
  1175. {
  1176. protection = 2;
  1177. input = CC_ParseToken( input );
  1178. Assert( !stricmp( com_token, ":" ) );
  1179. return true;
  1180. }
  1181. return false;
  1182. }
  1183. // parse until } found
  1184. // public:, private:, protected: set protection mode, private is initial default
  1185. // if token is not one of those, then parse and concatenate all tokens up to the first
  1186. // ; or (
  1187. //
  1188. char *CClass::ParseClassDeclaration( char *input )
  1189. {
  1190. int nestcount = 1;
  1191. // public = 0, protected = 1, private = 2;
  1192. int protection = 2;
  1193. do
  1194. {
  1195. input = CC_ParseToken( input );
  1196. if ( strlen( com_token ) <= 0 )
  1197. break;
  1198. if ( com_token[ 1 ] == 0 )
  1199. {
  1200. if ( com_token[ 0 ] == '{' )
  1201. {
  1202. nestcount++;
  1203. }
  1204. else if ( com_token[ 0 ] == '}' )
  1205. {
  1206. nestcount--;
  1207. }
  1208. }
  1209. if ( ParseProtection( input, protection ) )
  1210. continue;
  1211. if ( !stricmp( com_token, ";" ) )
  1212. continue;
  1213. if ( com_token[0] == '#' )
  1214. {
  1215. // swallow rest of line
  1216. input = CC_ParseUntilEndOfLine( input );
  1217. continue;
  1218. }
  1219. if ( ParseNestedClass( input ) )
  1220. continue;
  1221. if ( nestcount == 1 )
  1222. {
  1223. // See if we found a line that describes the base class
  1224. if ( ParseBaseClass( input ) )
  1225. continue;
  1226. ParseClassMember( input, protection );
  1227. }
  1228. } while ( nestcount != 0 && ( strlen( com_token ) >= 0 ) );
  1229. return input;
  1230. }
  1231. static bool ShouldHungarianCheck( char const *name )
  1232. {
  1233. if ( !Q_strncmp( name, "m_", 2 ) ||
  1234. !Q_strncmp( name, "g_", 2 ) ||
  1235. !Q_strncmp( name, "s_", 2 ) )
  1236. {
  1237. return true;
  1238. }
  1239. return false;
  1240. }
  1241. enum Required
  1242. {
  1243. NEVER = 0,
  1244. ALWAYS
  1245. };
  1246. struct Impermissible
  1247. {
  1248. char const *prefix;
  1249. char const *mustinclude;
  1250. int required; // if true, then must match to be permitted
  1251. };
  1252. static Impermissible g_Permissibles[] =
  1253. {
  1254. { "fl", "float", ALWAYS },
  1255. { "b", "bool", ALWAYS },
  1256. { "n", "int", ALWAYS },
  1257. { "isz", "string_t", ALWAYS },
  1258. { "i", "float", NEVER },
  1259. { "i", "bool", NEVER },
  1260. { "i", "short", NEVER },
  1261. { "i", "long", NEVER },
  1262. { "ui", "int", ALWAYS },
  1263. { "sz", "char", ALWAYS },
  1264. { "ch", "char", ALWAYS },
  1265. { "uch", "float", NEVER },
  1266. { "uch", "int", NEVER },
  1267. { "uch", "short", NEVER },
  1268. { "uch", "long", NEVER },
  1269. { "s", "short", ALWAYS },
  1270. { "us", "short", ALWAYS },
  1271. { "l", "long", ALWAYS },
  1272. { "ul", "long", ALWAYS },
  1273. // { "f", "int", NEVER },
  1274. // { "f", "short", NEVER },
  1275. // { "f", "int", NEVER },
  1276. { "a", "UtlVector", ALWAYS },
  1277. { "h", "handle", ALWAYS },
  1278. { "p", "*", ALWAYS },
  1279. };
  1280. void CClass::CheckForHungarianErrors( int& warnings )
  1281. {
  1282. int testcount = sizeof( g_Permissibles ) / sizeof( g_Permissibles[ 0 ] );
  1283. for ( int i = 0; i < m_nVarCount; i++ )
  1284. {
  1285. CClassVariable *var = m_Variables[ i ];
  1286. // Only check m_, s_, and g_ variables for now
  1287. if ( !ShouldHungarianCheck( var->m_szName ) )
  1288. {
  1289. continue;
  1290. }
  1291. bool isstatic = false;
  1292. char *p = var->m_szType;
  1293. while ( 1 )
  1294. {
  1295. p = CC_ParseToken( p );
  1296. if ( strlen( com_token ) <= 0 )
  1297. break;
  1298. if ( !stricmp( com_token, "static" ) )
  1299. {
  1300. isstatic = true;
  1301. break;
  1302. }
  1303. }
  1304. // Check for errors
  1305. for ( int j = 0; j < testcount; ++j )
  1306. {
  1307. Impermissible *tst = &g_Permissibles[ j ];
  1308. bool match = !Q_strncmp( var->m_szName + 2, tst->prefix, Q_strlen( tst->prefix ) ) ? true : false;
  1309. if ( !match )
  1310. continue;
  1311. // The first character after the prefix must be upper case or we skip...
  1312. int nextchar = 2 + Q_strlen( tst->prefix );
  1313. if ( !isupper( var->m_szName[ nextchar ] ) )
  1314. continue;
  1315. bool typeFound = Q_stristr( var->m_szType, tst->mustinclude ) ? true : false;
  1316. switch ( tst->required )
  1317. {
  1318. default:
  1319. case ALWAYS:
  1320. {
  1321. if ( !typeFound )
  1322. {
  1323. vprint( 1, "%s might have wrong type %s\n", var->m_szName, var->m_szType );
  1324. ++warnings;
  1325. }
  1326. else
  1327. {
  1328. return;
  1329. }
  1330. }
  1331. break;
  1332. case NEVER:
  1333. {
  1334. if ( typeFound )
  1335. {
  1336. vprint( 1, "%s might have wrong type %s\n", var->m_szName, var->m_szType );
  1337. ++warnings;
  1338. }
  1339. else
  1340. {
  1341. return;
  1342. }
  1343. }
  1344. break;
  1345. }
  1346. }
  1347. if ( !Q_strncmp( var->m_szName, "m_f", 3 ) &&
  1348. Q_strncmp( var->m_szName, "m_fl", 4 ) && isupper( var->m_szName[3] ) )
  1349. {
  1350. // If it's a "flag" and not a "float" type, it better be a bool or an int
  1351. if ( !Q_stristr( var->m_szType, "bool" ) &&
  1352. !Q_strstr( var->m_szType, "int" ) )
  1353. {
  1354. vprint( 1, "%s might have wrong type %s\n", var->m_szName, var->m_szType );
  1355. ++warnings;
  1356. return;
  1357. }
  1358. }
  1359. }
  1360. }