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.

1865 lines
39 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <assert.h>
  8. #include <time.h>
  9. #include "stdafx.h"
  10. #include <stdio.h>
  11. #include <windows.h>
  12. #include "classcheck_util.h"
  13. #include "codeprocessor.h"
  14. /*
  15. ================
  16. UTIL_FloatTime
  17. ================
  18. */
  19. double UTIL_FloatTime (void)
  20. {
  21. // more precise, less portable
  22. clock_t current;
  23. static clock_t base;
  24. static bool first = true;
  25. current = clock();
  26. if ( first )
  27. {
  28. first = false;
  29. base = current;
  30. }
  31. return (double)(current - base)/(double)CLOCKS_PER_SEC;
  32. }
  33. CClass *CCodeProcessor::FindClass( const char *name ) const
  34. {
  35. CClass *cl = m_pClassList;
  36. while ( cl )
  37. {
  38. if ( !stricmp( cl->m_szName, name ) )
  39. return cl;
  40. cl = cl->m_pNext;
  41. }
  42. return NULL;
  43. }
  44. void ClearMissingTypes();
  45. void CCodeProcessor::Clear( void )
  46. {
  47. ClearMissingTypes();
  48. CClass *cl = m_pClassList, *next;
  49. while ( cl )
  50. {
  51. next = cl->m_pNext;
  52. delete cl;
  53. cl = next;
  54. }
  55. m_pClassList = NULL;
  56. }
  57. int CCodeProcessor::Count( void ) const
  58. {
  59. int c = 0;
  60. CClass *cl = m_pClassList;
  61. while ( cl )
  62. {
  63. c++;
  64. cl = cl->m_pNext;
  65. }
  66. return c;
  67. }
  68. int FnClassSortCompare( const void *elem1, const void *elem2 )
  69. {
  70. CClass *c1 = *(CClass **)elem1;
  71. CClass *c2 = *(CClass **)elem2;
  72. return ( stricmp( c1->m_szName, c2->m_szName ) );
  73. }
  74. void CCodeProcessor::SortClassList( void )
  75. {
  76. int n = Count();
  77. if ( n <= 1 )
  78. return;
  79. CClass **ppList = new CClass *[ n ];
  80. if ( ppList )
  81. {
  82. CClass *cl;
  83. int i;
  84. for ( i = 0, cl = m_pClassList; i < n; i++, cl = cl->m_pNext )
  85. {
  86. ppList[ i ] = cl;
  87. }
  88. qsort( ppList, n, sizeof( CClass * ), FnClassSortCompare );
  89. for ( i = 0; i < n - 1; i++ )
  90. {
  91. ppList[ i ]->m_pNext = ppList[ i + 1 ];
  92. }
  93. ppList[ i ]->m_pNext = NULL;
  94. m_pClassList = ppList[ 0 ];
  95. }
  96. delete[] ppList;
  97. }
  98. void CCodeProcessor::ResolveBaseClasses( const char *baseentityclass )
  99. {
  100. SortClassList();
  101. CClass *cl = m_pClassList;
  102. while ( cl )
  103. {
  104. if ( cl->m_szBaseClass[0] )
  105. {
  106. cl->m_pBaseClass = FindClass( cl->m_szBaseClass );
  107. if ( !cl->m_pBaseClass )
  108. {
  109. //vprint( 0, "couldn't find base class %s for %s\n", cl->m_szBaseClass, cl->m_szName );
  110. }
  111. }
  112. cl = cl->m_pNext;
  113. }
  114. cl = m_pClassList;
  115. while ( cl )
  116. {
  117. cl->CheckChildOfBaseEntity( baseentityclass );
  118. cl = cl->m_pNext;
  119. }
  120. }
  121. void CCodeProcessor::PrintMissingTDFields( void ) const
  122. {
  123. int classcount;
  124. int fieldcount;
  125. int c;
  126. CClass *cl;
  127. if ( GetPrintTDs() )
  128. {
  129. classcount = 0;
  130. fieldcount = 0;
  131. cl = m_pClassList;
  132. while ( cl )
  133. {
  134. if ( cl->m_bDerivedFromCBaseEntity || cl->m_bHasSaveRestoreData )
  135. {
  136. if ( cl->CheckForMissingTypeDescriptionFields( c ) )
  137. {
  138. classcount++;
  139. fieldcount += c;
  140. }
  141. }
  142. cl = cl->m_pNext;
  143. }
  144. if ( fieldcount )
  145. {
  146. vprint( 0, "\nSummary: %i fields missing from %i classes\n", fieldcount, classcount );
  147. }
  148. else
  149. {
  150. if ( !classcount )
  151. {
  152. vprint( 0, "\nSummary: no saverestore info present\n");
  153. }
  154. else
  155. {
  156. vprint( 0, "\nSummary: no errors for %i classes\n", classcount );
  157. }
  158. }
  159. vprint( 0, "\n" );
  160. }
  161. if ( GetPrintPredTDs() )
  162. {
  163. //Now check prediction stuff
  164. classcount = 0;
  165. fieldcount = 0;
  166. cl = m_pClassList;
  167. while ( cl )
  168. {
  169. if ( cl->m_bDerivedFromCBaseEntity || cl->m_bHasPredictionData )
  170. {
  171. if ( cl->CheckForMissingPredictionFields( c, false ) )
  172. {
  173. classcount++;
  174. fieldcount += c;
  175. }
  176. }
  177. cl = cl->m_pNext;
  178. }
  179. if ( fieldcount )
  180. {
  181. vprint( 0, "\nSummary: %i prediction fields missing from %i classes\n", fieldcount, classcount );
  182. }
  183. else
  184. {
  185. if ( !classcount )
  186. {
  187. vprint( 0, "\nSummary: no prediction info present\n");
  188. }
  189. else
  190. {
  191. vprint( 0, "\nSummary: no errors for %i predictable classes\n", classcount );
  192. }
  193. }
  194. vprint( 0, "\n" );
  195. }
  196. if ( GetPrintCreateMissingTDs() )
  197. {
  198. //Now check prediction stuff
  199. classcount = 0;
  200. fieldcount = 0;
  201. cl = m_pClassList;
  202. while ( cl )
  203. {
  204. if ( cl->m_bDerivedFromCBaseEntity || cl->m_bHasSaveRestoreData )
  205. {
  206. if ( cl->CheckForMissingTypeDescriptionFields( c, true ) )
  207. {
  208. classcount++;
  209. fieldcount += c;
  210. }
  211. }
  212. cl = cl->m_pNext;
  213. }
  214. if ( fieldcount )
  215. {
  216. vprint( 0, "\nSummary: %i saverestore fields missing from %i classes\n", fieldcount, classcount );
  217. }
  218. else
  219. {
  220. if ( !classcount )
  221. {
  222. vprint( 0, "\nSummary: no saverestore info present\n");
  223. }
  224. else
  225. {
  226. vprint( 0, "\nSummary: no errors for %i classes\n", classcount );
  227. }
  228. }
  229. vprint( 0, "\n" );
  230. }
  231. if ( GetPrintCreateMissingPredTDs() )
  232. {
  233. //Now check prediction stuff
  234. classcount = 0;
  235. fieldcount = 0;
  236. cl = m_pClassList;
  237. while ( cl )
  238. {
  239. if ( cl->m_bDerivedFromCBaseEntity || cl->m_bHasPredictionData )
  240. {
  241. if ( cl->CheckForMissingPredictionFields( c, true ) )
  242. {
  243. classcount++;
  244. fieldcount += c;
  245. }
  246. }
  247. cl = cl->m_pNext;
  248. }
  249. if ( fieldcount )
  250. {
  251. vprint( 0, "\nSummary: %i prediction fields missing from %i classes\n", fieldcount, classcount );
  252. }
  253. else
  254. {
  255. if ( !classcount )
  256. {
  257. vprint( 0, "\nSummary: no prediction info present\n");
  258. }
  259. else
  260. {
  261. vprint( 0, "\nSummary: no errors for %i predictable classes\n", classcount );
  262. }
  263. }
  264. vprint( 0, "\n" );
  265. }
  266. // Now check for things that are in the prediction TD but not marked correctly as being part of the sendtable
  267. {
  268. //Now check prediction stuff
  269. classcount = 0;
  270. fieldcount = 0;
  271. cl = m_pClassList;
  272. while ( cl )
  273. {
  274. if ( cl->m_bDerivedFromCBaseEntity || cl->m_bHasPredictionData )
  275. {
  276. if ( cl->CheckForPredictionFieldsInRecvTableNotMarkedAsSuchCorrectly( c ) )
  277. {
  278. classcount++;
  279. fieldcount += c;
  280. }
  281. }
  282. cl = cl->m_pNext;
  283. }
  284. vprint( 0, "\n" );
  285. }
  286. // Print stuff derived from CBaseEntity that doesn't have save/restore data
  287. vprint( 0, "\nMissing DATADESC tables:\n\n" );
  288. cl = m_pClassList;
  289. while ( cl )
  290. {
  291. if ( cl->m_bDerivedFromCBaseEntity && !cl->m_bHasSaveRestoreData && cl->m_nVarCount )
  292. {
  293. vprint( 0, "\t%s\n", cl->m_szName );
  294. }
  295. cl = cl->m_pNext;
  296. }
  297. vprint( 0, "\n" );
  298. }
  299. void CCodeProcessor::ReportHungarianNotationErrors()
  300. {
  301. if ( !GetCheckHungarian() )
  302. return;
  303. vprint( 0, "\tChecking for hungarian notation issues\n" );
  304. CClass *cl = m_pClassList;
  305. int classcount = 0;
  306. int warningcount = 0;
  307. while ( cl )
  308. {
  309. int c = 0;
  310. cl->CheckForHungarianErrors( c );
  311. classcount++;
  312. warningcount += c;
  313. cl = cl->m_pNext;
  314. }
  315. vprint( 0, "\tFound %i notation errors across %i classes\n", classcount, warningcount );
  316. }
  317. void CCodeProcessor::PrintClassList( void ) const
  318. {
  319. if ( GetPrintHierarchy() )
  320. {
  321. vprint( 0, "\nClass Summary\n\n" );
  322. }
  323. CClass *cl = m_pClassList;
  324. while ( cl )
  325. {
  326. if ( cl->m_bDerivedFromCBaseEntity )
  327. {
  328. bool missing = false;
  329. char missingwarning[ 128 ];
  330. missingwarning[0]=0;
  331. if ( cl->m_szTypedefBaseClass[0] )
  332. {
  333. if ( stricmp( cl->m_szBaseClass, cl->m_szTypedefBaseClass ) )
  334. {
  335. vprint( 0, "class %s has incorrect typedef %s BaseClass\n", cl->m_szName, cl->m_szTypedefBaseClass );
  336. }
  337. }
  338. else if ( cl->m_szBaseClass[ 0 ] )
  339. {
  340. missing = true;
  341. sprintf( missingwarning, ", missing typedef %s BaseClass", cl->m_szBaseClass );
  342. }
  343. if ( GetPrintHierarchy() || missing )
  344. {
  345. vprint( 0, "class %s%s\n", cl->m_szName, missing ? missingwarning : "" );
  346. }
  347. int level = 1;
  348. CClass *base = cl->m_pBaseClass;
  349. while ( base )
  350. {
  351. if ( GetPrintHierarchy() )
  352. {
  353. vprint( level++, "public %s\n", base->m_szName );
  354. }
  355. base = base->m_pBaseClass;
  356. }
  357. int i;
  358. if ( GetPrintHierarchy() && GetPrintMembers() )
  359. {
  360. if ( cl->m_nMemberCount )
  361. {
  362. vprint( 1, "\nMember functions:\n\n" );
  363. }
  364. for ( i = 0; i < cl->m_nMemberCount; i++ )
  365. {
  366. CClassMemberFunction *member = cl->m_Members[ i ];
  367. if ( member->m_szType[0] )
  368. {
  369. vprint( 1, "%s %s();\n", member->m_szType, member->m_szName );
  370. }
  371. else
  372. {
  373. char *p = member->m_szName;
  374. if ( *p == '~' )
  375. p++;
  376. if ( stricmp( p, cl->m_szName ) )
  377. {
  378. vprint( 0, "class %s has member function %s with no return type!!!\n",
  379. cl->m_szName, member->m_szName );
  380. }
  381. vprint( 1, "%s();\n", member->m_szName );
  382. }
  383. }
  384. if ( cl->m_nVarCount )
  385. {
  386. vprint( 1, "\nMember Variables\n\n" );
  387. }
  388. for ( i = 0; i < cl->m_nVarCount; i++ )
  389. {
  390. CClassVariable *var = cl->m_Variables[ i ];
  391. if ( var->m_bIsArray )
  392. {
  393. if ( var->m_szArraySize[0]==0 )
  394. {
  395. vprint( 1, "%s %s[];\n", var->m_szType, var->m_szName );
  396. }
  397. else
  398. {
  399. vprint( 1, "%s %s[ %s ];\n", var->m_szType, var->m_szName, var->m_szArraySize );
  400. }
  401. }
  402. else
  403. {
  404. vprint( 1, "%s %s;\n", var->m_szType, var->m_szName );
  405. }
  406. }
  407. if ( cl->m_nTDCount )
  408. {
  409. vprint( 1, "\nSave/Restore TYPEDESCRIPTION\n\n" );
  410. }
  411. for ( i = 0; i < cl->m_nTDCount; i++ )
  412. {
  413. CTypeDescriptionField *td = cl->m_TDFields[ i ];
  414. if ( td->m_bCommentedOut )
  415. {
  416. vprint( 1, "// " );
  417. }
  418. else
  419. {
  420. vprint( 1, "" );
  421. }
  422. vprint( 0, "%s( %s, %s, %s, ... )\n", td->m_szDefineType, cl->m_szName, td->m_szVariableName, td->m_szType );
  423. }
  424. if ( !cl->m_bHasSaveRestoreData )
  425. {
  426. // vprint( 1, "\nSave/Restore TYPEDESCRIPTION not specified for class\n\n" );
  427. }
  428. if ( cl->m_nPredTDCount )
  429. {
  430. vprint( 1, "\nPrediction TYPEDESCRIPTION\n\n" );
  431. }
  432. for ( i = 0; i < cl->m_nPredTDCount; i++ )
  433. {
  434. CTypeDescriptionField *td = cl->m_PredTDFields[ i ];
  435. if ( td->m_bCommentedOut )
  436. {
  437. vprint( 1, "// " );
  438. }
  439. else
  440. {
  441. vprint( 1, "" );
  442. }
  443. vprint( 0, "%s( %s, %s, %s, ... )\n", td->m_szDefineType, cl->m_szName, td->m_szVariableName, td->m_szType );
  444. }
  445. if ( !cl->m_bHasPredictionData )
  446. {
  447. // vprint( 1, "\nPrediction TYPEDESCRIPTION not specified for class\n\n" );
  448. }
  449. }
  450. if ( GetPrintHierarchy() )
  451. {
  452. vprint( 0, "\n" );
  453. }
  454. }
  455. cl = cl->m_pNext;
  456. }
  457. }
  458. CClass *CCodeProcessor::AddClass( const char *classname )
  459. {
  460. CClass *cl = FindClass( classname );
  461. if ( !cl )
  462. {
  463. cl = new CClass( classname );
  464. m_nClassesParsed++;
  465. cl->m_pNext = m_pClassList;
  466. m_pClassList = cl;
  467. }
  468. return cl;
  469. }
  470. char *CCodeProcessor::ParseTypeDescription( char *current, bool fIsMacroized )
  471. {
  472. // Next token is classname then :: then variablename then braces then = then {
  473. char classname[ 256 ];
  474. char variablename[ 256 ];
  475. if ( !fIsMacroized )
  476. {
  477. current = CC_ParseToken( current );
  478. if ( strlen( com_token ) <= 0 )
  479. return current;
  480. strcpy( classname, com_token );
  481. if ( classname[0]=='*' )
  482. return current;
  483. current = CC_ParseToken( current );
  484. if (stricmp( com_token, ":" ) )
  485. {
  486. return current;
  487. }
  488. current = CC_ParseToken( current );
  489. Assert( !stricmp( com_token, ":" ) );
  490. current = CC_ParseToken( current );
  491. if ( strlen( com_token ) <= 0 )
  492. return current;
  493. strcpy( variablename, com_token );
  494. }
  495. else
  496. {
  497. current = CC_ParseToken( current );
  498. if (stricmp( com_token, "(" ) )
  499. {
  500. return current;
  501. }
  502. current = CC_ParseToken( current );
  503. if ( strlen( com_token ) <= 0 )
  504. return current;
  505. strcpy( classname, com_token );
  506. if ( classname[0]=='*' )
  507. return current;
  508. current = CC_ParseToken( current );
  509. if (stricmp( com_token, ")" ) )
  510. {
  511. return current;
  512. }
  513. // It's macro-ized
  514. strcpy( variablename, "m_DataDesc" );
  515. }
  516. if ( !fIsMacroized )
  517. {
  518. char ch;
  519. current = CC_RawParseChar( current, "{", &ch );
  520. Assert( ch == '{' );
  521. if ( strlen( com_token ) <= 0 )
  522. return current;
  523. }
  524. com_ignoreinlinecomment = true;
  525. bool insidecomment = false;
  526. // Now parse typedescription line by line
  527. while ( 1 )
  528. {
  529. current = CC_ParseToken( current );
  530. if ( strlen( com_token ) <= 0 )
  531. break;
  532. // Go to next line
  533. if ( !stricmp( com_token, "," ) )
  534. continue;
  535. // end
  536. if ( !fIsMacroized )
  537. {
  538. if ( !stricmp( com_token, "}" ) )
  539. break;
  540. }
  541. else
  542. {
  543. if ( !stricmp( com_token, "END_DATADESC" ) ||
  544. !stricmp( com_token, "END_BYTESWAP_DATADESC" ) )
  545. break;
  546. }
  547. // skip #ifdef's inside of typedescs
  548. if ( com_token[0]=='#' )
  549. {
  550. current = CC_ParseUntilEndOfLine( current );
  551. continue;
  552. }
  553. if ( !stricmp( com_token, "/" ) )
  554. {
  555. current = CC_ParseToken( current );
  556. if ( !stricmp( com_token, "/" ) )
  557. {
  558. // There are two styles supported. One is to have the member definition present but commented out:
  559. // DEFINE_FIELD( m_member, FIELD_INTEGER ),
  560. // the other is to have a comment where the first token of the comment is a member name:
  561. // m_member
  562. current = CC_ParseToken( current );
  563. if ( !strnicmp( com_token, "DEFINE_", 7 ) )
  564. {
  565. CC_UngetToken();
  566. insidecomment = true;
  567. }
  568. else
  569. {
  570. char commentedvarname[ 256 ];
  571. strcpy( commentedvarname, com_token );
  572. CClass *cl = FindClass( classname );
  573. if ( cl )
  574. {
  575. if ( !cl->FindTD( commentedvarname ) )
  576. {
  577. cl->AddTD( commentedvarname, "", "", true );
  578. }
  579. // Mark that it has a data table
  580. cl->m_bHasSaveRestoreData = true;
  581. }
  582. current = CC_ParseUntilEndOfLine( current );
  583. }
  584. continue;
  585. }
  586. }
  587. com_ignoreinlinecomment = false;
  588. // Parse a typedescription line
  589. char definetype[ 256 ];
  590. strcpy( definetype, com_token );
  591. current = CC_ParseToken( current );
  592. if ( stricmp( com_token, "(" ) )
  593. break;
  594. char varname[ 256 ];
  595. current = CC_ParseToken( current );
  596. strcpy( varname, com_token );
  597. char vartype[ 256 ];
  598. vartype[0]=0;
  599. if ( !stricmp( definetype, "DEFINE_FUNCTION" ) ||
  600. !stricmp( definetype, "DEFINE_THINKFUNC" ) ||
  601. !stricmp( definetype, "DEFINE_ENTITYFUNC" ) ||
  602. !stricmp( definetype, "DEFINE_USEFUNC" ) ||
  603. !stricmp( definetype, "DEFINE_OUTPUT" ) ||
  604. !stricmp( definetype, "DEFINE_INPUTFUNC" ) )
  605. {
  606. strcpy( vartype, "funcptr" );
  607. }
  608. else if ( !stricmp(definetype, "DEFINE_FIELD") ||
  609. !stricmp(definetype, "DEFINE_INDEX") ||
  610. !stricmp(definetype, "DEFINE_KEYFIELD") ||
  611. !stricmp(definetype, "DEFINE_KEYFIELD_NOT_SAVED") ||
  612. !stricmp(definetype, "DEFINE_UTLVECTOR") ||
  613. !stricmp(definetype, "DEFINE_GLOBAL_FIELD") ||
  614. !stricmp(definetype, "DEFINE_GLOBAL_KEYFIELD") ||
  615. !stricmp(definetype, "DEFINE_CUSTOM_FIELD") ||
  616. !stricmp(definetype, "DEFINE_INPUT") ||
  617. !stricmp(definetype, "DEFINE_AUTO_ARRAY") ||
  618. !stricmp(definetype, "DEFINE_AUTO_ARRAY_KEYFIELD") ||
  619. !stricmp(definetype, "DEFINE_AUTO_ARRAY2D") ||
  620. !stricmp(definetype, "DEFINE_ARRAY") )
  621. {
  622. // skip comma
  623. current = CC_ParseToken( current );
  624. if (!strcmp( com_token, "[" ))
  625. {
  626. // Read array...
  627. current = CC_ParseToken( current );
  628. strcat( varname, "[" );
  629. strcat( varname, com_token );
  630. current = CC_ParseToken( current );
  631. // eat everything until the next "]"
  632. while (strcmp( com_token, "]") != 0)
  633. {
  634. strcat( varname, com_token );
  635. current = CC_ParseToken( current );
  636. }
  637. if ( strcmp( com_token, "]" ))
  638. {
  639. current = current;
  640. }
  641. strcat( varname, "]" );
  642. // skip comma
  643. current = CC_ParseToken( current );
  644. }
  645. current = CC_ParseToken( current );
  646. strcpy( vartype, com_token );
  647. }
  648. // Jump to end of definition
  649. int nParenCount = 1;
  650. do
  651. {
  652. current = CC_ParseToken( current );
  653. if ( strlen( com_token ) <= 0 )
  654. break;
  655. if ( !stricmp( com_token, "(" ) )
  656. {
  657. ++nParenCount;
  658. }
  659. else if ( !stricmp( com_token, ")" ) )
  660. {
  661. if ( --nParenCount == 0 )
  662. {
  663. break;
  664. }
  665. }
  666. } while ( 1 );
  667. // vprint( 2, "%s%s::%s %s %s %s\n",
  668. // insidecomment ? "// " : "",
  669. // classname, variablename,
  670. // definetype, varname, vartype );
  671. CClass *cl = FindClass( classname );
  672. if ( cl )
  673. {
  674. if ( strcmp( vartype, "funcptr" ) && cl->FindTD( varname ) )
  675. {
  676. vprint( 0, "class %s::%s already has typedescription entry for field %s\n", classname, variablename, varname );
  677. }
  678. else
  679. {
  680. cl->AddTD( varname, vartype, definetype, insidecomment );
  681. }
  682. // Mark that it has a data table
  683. cl->m_bHasSaveRestoreData = true;
  684. }
  685. insidecomment = false;
  686. com_ignoreinlinecomment = true;
  687. }
  688. com_ignoreinlinecomment = false;
  689. return current;
  690. }
  691. char *CCodeProcessor::ParseReceiveTable( char *current )
  692. {
  693. // Next token is open paren, then classname close paren, then {
  694. char classname[ 256 ];
  695. current = CC_ParseToken( current );
  696. if (stricmp( com_token, "(" ) )
  697. {
  698. return current;
  699. }
  700. current = CC_ParseToken( current );
  701. if ( strlen( com_token ) <= 0 )
  702. return current;
  703. strcpy( classname, com_token );
  704. if ( classname[0]=='*' )
  705. return current;
  706. if ( !strcmp( classname, "className" ) )
  707. return current;
  708. if ( !strcmp( classname, "clientClassName" ) )
  709. return current;
  710. CClass *cl = FindClass( classname );
  711. if ( cl )
  712. {
  713. cl->m_bHasRecvTableData = true;
  714. }
  715. CClass *leafClass = cl;
  716. // parse until end of line
  717. current = CC_ParseUntilEndOfLine( current );
  718. // Now parse recvtable entries line by line
  719. while ( 1 )
  720. {
  721. cl = leafClass;
  722. current = CC_ParseToken( current );
  723. if ( strlen( com_token ) <= 0 )
  724. break;
  725. // Go to next line
  726. if ( !stricmp( com_token, "," ) )
  727. continue;
  728. // end
  729. if ( !stricmp( com_token, "END_RECV_TABLE" ) )
  730. break;
  731. // skip #ifdef's inside of recv tables
  732. if ( com_token[0]=='#' )
  733. {
  734. current = CC_ParseUntilEndOfLine( current );
  735. continue;
  736. }
  737. // Parse recproxy line
  738. char recvproptype[ 256 ];
  739. strcpy( recvproptype, com_token );
  740. if ( strnicmp( recvproptype, "RecvProp", strlen( "RecvProp" ) ) )
  741. {
  742. current = CC_ParseUntilEndOfLine( current );
  743. continue;
  744. }
  745. if ( !strcmp( recvproptype, "RecvPropArray" ) )
  746. {
  747. current = CC_ParseToken( current );
  748. if ( stricmp( com_token, "(" ) )
  749. break;
  750. current = CC_ParseToken( current );
  751. if ( strnicmp( recvproptype, "RecvProp", strlen( "RecvProp" ) ) )
  752. {
  753. current = CC_ParseUntilEndOfLine( current );
  754. continue;
  755. }
  756. }
  757. current = CC_ParseToken( current );
  758. if ( stricmp( com_token, "(" ) )
  759. break;
  760. // Read macro or fieldname
  761. current = CC_ParseToken( current );
  762. char varname[ 256 ];
  763. if ( !strnicmp( com_token, "RECVINFO", strlen( "RECVINFO" ) ) )
  764. {
  765. current = CC_ParseToken( current );
  766. if ( stricmp( com_token, "(" ) )
  767. break;
  768. current = CC_ParseToken( current );
  769. }
  770. else
  771. {
  772. current = CC_ParseUntilEndOfLine( current );
  773. continue;
  774. }
  775. strcpy( varname, com_token );
  776. current = CC_ParseUntilEndOfLine( current );
  777. if ( cl )
  778. {
  779. // Look up the var
  780. CClassVariable *classVar = cl->FindVar( varname, true );
  781. if ( classVar )
  782. {
  783. classVar->m_bInRecvTable = true;
  784. }
  785. else
  786. {
  787. char cropped[ 256 ];
  788. char root[ 256 ];
  789. strcpy( cropped, varname );
  790. while ( 1 )
  791. {
  792. // See if varname is an embedded var
  793. char *spot = strstr( cropped, "." );
  794. if ( spot )
  795. {
  796. strcpy( root, cropped );
  797. root[ spot - cropped ] = 0;
  798. strcpy( cropped, spot + 1 );
  799. classVar = cl->FindVar( root, true );
  800. }
  801. else
  802. {
  803. classVar = cl->FindVar( cropped, true );
  804. break;
  805. }
  806. if ( classVar )
  807. break;
  808. }
  809. if ( !classVar )
  810. {
  811. vprint( 0, "class %s::%s missing, but referenced by RecvTable!!!\n", classname, varname );
  812. }
  813. else
  814. {
  815. classVar->m_bInRecvTable = true;
  816. }
  817. }
  818. }
  819. else
  820. {
  821. vprint( 0, "class %s::%s found in RecvTable, but no such class is known!!!\n", classname, varname );
  822. }
  823. }
  824. return current;
  825. }
  826. char *CCodeProcessor::ParsePredictionTypeDescription( char *current )
  827. {
  828. // Next token is open paren, then classname close paren, then {
  829. char classname[ 256 ];
  830. char variablename[ 256 ];
  831. current = CC_ParseToken( current );
  832. if (stricmp( com_token, "(" ) )
  833. {
  834. return current;
  835. }
  836. current = CC_ParseToken( current );
  837. if ( strlen( com_token ) <= 0 )
  838. return current;
  839. strcpy( classname, com_token );
  840. if ( classname[0]=='*' )
  841. return current;
  842. CClass *cl = FindClass( classname );
  843. if ( cl )
  844. {
  845. cl->m_bHasPredictionData = true;
  846. }
  847. current = CC_ParseToken( current );
  848. if (stricmp( com_token, ")" ) )
  849. {
  850. return current;
  851. }
  852. // It's macro-ized
  853. strcpy( variablename, "m_PredDesc" );
  854. com_ignoreinlinecomment = true;
  855. bool insidecomment = false;
  856. // Now parse typedescription line by line
  857. while ( 1 )
  858. {
  859. current = CC_ParseToken( current );
  860. if ( strlen( com_token ) <= 0 )
  861. break;
  862. // Go to next line
  863. if ( !stricmp( com_token, "," ) )
  864. continue;
  865. // end
  866. if ( !stricmp( com_token, "END_PREDICTION_DATA" ) )
  867. break;
  868. // skip #ifdef's inside of typedescs
  869. if ( com_token[0]=='#' )
  870. {
  871. current = CC_ParseUntilEndOfLine( current );
  872. continue;
  873. }
  874. if ( !stricmp( com_token, "/" ) )
  875. {
  876. current = CC_ParseToken( current );
  877. if ( !stricmp( com_token, "/" ) )
  878. {
  879. current = CC_ParseToken( current );
  880. if ( !strnicmp( com_token, "DEFINE_", 7 ) )
  881. {
  882. CC_UngetToken();
  883. insidecomment = true;
  884. }
  885. else
  886. {
  887. current = CC_ParseUntilEndOfLine( current );
  888. }
  889. continue;
  890. }
  891. }
  892. com_ignoreinlinecomment = false;
  893. // Parse a typedescription line
  894. char definetype[ 256 ];
  895. strcpy( definetype, com_token );
  896. current = CC_ParseToken( current );
  897. if ( stricmp( com_token, "(" ) )
  898. break;
  899. char varname[ 256 ];
  900. current = CC_ParseToken( current );
  901. strcpy( varname, com_token );
  902. char vartype[ 256 ];
  903. vartype[0]=0;
  904. if ( stricmp( definetype, "DEFINE_FUNCTION" ) )
  905. {
  906. // skip comma
  907. current = CC_ParseToken( current );
  908. current = CC_ParseToken( current );
  909. strcpy( vartype, com_token );
  910. }
  911. else
  912. {
  913. strcpy( vartype, "funcptr" );
  914. }
  915. bool inrecvtable = false;
  916. // Jump to end of definition
  917. int nParenCount = 1;
  918. do
  919. {
  920. current = CC_ParseToken( current );
  921. if ( strlen( com_token ) <= 0 )
  922. break;
  923. if ( !stricmp( com_token, "(" ) )
  924. {
  925. ++nParenCount;
  926. }
  927. else if ( !stricmp( com_token, ")" ) )
  928. {
  929. if ( --nParenCount == 0 )
  930. {
  931. break;
  932. }
  933. }
  934. if ( !stricmp( com_token, "FTYPEDESC_INSENDTABLE" ) )
  935. {
  936. inrecvtable = true;
  937. }
  938. } while ( 1 );
  939. /*
  940. vprint( 2, "%s%s::%s %s %s %s\n",
  941. insidecomment ? "// " : "",
  942. classname, variablename,
  943. definetype, varname, vartype );
  944. */
  945. if ( cl )
  946. {
  947. if ( cl->FindPredTD( varname ) )
  948. {
  949. vprint( 0, "class %s::%s already has prediction typedescription entry for field %s\n", classname, variablename, varname );
  950. }
  951. else
  952. {
  953. cl->AddPredTD( varname, vartype, definetype, insidecomment, inrecvtable );
  954. }
  955. }
  956. insidecomment = false;
  957. com_ignoreinlinecomment = true;
  958. }
  959. com_ignoreinlinecomment = false;
  960. return current;
  961. }
  962. void CCodeProcessor::AddHeader( int depth, const char *filename, const char *rootmodule )
  963. {
  964. // if ( depth < 1 )
  965. // return;
  966. if ( depth != 1 )
  967. return;
  968. // Check header list
  969. int idx = m_Headers.Find( filename );
  970. if ( idx != m_Headers.InvalidIndex() )
  971. {
  972. vprint( 0, "%s included twice in module %s\n", filename, rootmodule );
  973. return;
  974. }
  975. CODE_MODULE module;
  976. module.skipped = false;
  977. m_Headers.Insert( filename, module );
  978. }
  979. bool CCodeProcessor::CheckShouldSkip( bool forcequiet, int depth, char const *filename, int& numheaders, int& skippedfiles)
  980. {
  981. int idx = m_Modules.Find( filename );
  982. if ( idx == m_Modules.InvalidIndex() )
  983. return false;
  984. CODE_MODULE *module = &m_Modules[ idx ];
  985. if ( forcequiet )
  986. {
  987. m_nHeadersProcessed++;
  988. numheaders++;
  989. if ( module->skipped )
  990. {
  991. skippedfiles++;
  992. }
  993. }
  994. AddHeader( depth, filename, m_szCurrentCPP );
  995. return true;
  996. }
  997. bool CCodeProcessor::LoadFile( char **buffer, char *filename, char const *module, bool forcequiet,
  998. int depth, int& filelength, int& numheaders, int& skippedfiles,
  999. char const *srcroot, char const *root, char const *baseroot )
  1000. {
  1001. for ( int i = 0; i < m_IncludePath.Count(); ++i )
  1002. {
  1003. // Load the base module
  1004. sprintf( filename, "%s\\%s", m_IncludePath[i], module );
  1005. strlwr( filename );
  1006. if ( CheckShouldSkip( forcequiet, depth, filename, numheaders, skippedfiles ) )
  1007. {
  1008. return false;
  1009. }
  1010. *buffer = (char *)COM_LoadFile( filename, &filelength );
  1011. if ( *buffer )
  1012. return true;
  1013. }
  1014. return false;
  1015. }
  1016. static bool SkipFile( char const *module )
  1017. {
  1018. if ( !stricmp( module, "predictable_entity.h" ) )
  1019. return true;
  1020. if ( !stricmp( module, "baseentity_shared.h" ) )
  1021. return true;
  1022. if ( !stricmp( module, "baseplayer_shared.h" ) )
  1023. return true;
  1024. if ( !stricmp( module, "tf_tacticalmap.cpp" ) )
  1025. return true;
  1026. if ( !stricmp( module, "techtree.cpp" ) )
  1027. return true;
  1028. if ( !stricmp( module, "techtree_parse.cpp" ) )
  1029. return true;
  1030. return false;
  1031. }
  1032. void CCodeProcessor::ProcessModule( bool forcequiet, int depth, int& maxdepth, int& numheaders, int& skippedfiles,
  1033. const char *srcroot, const char *baseroot, const char *root, const char *module )
  1034. {
  1035. char filename[ 256 ];
  1036. if ( depth > maxdepth )
  1037. {
  1038. maxdepth = depth;
  1039. }
  1040. int filelength;
  1041. char *buffer = NULL;
  1042. // Always skip these particular modules/headers
  1043. if ( SkipFile( module ) )
  1044. {
  1045. CODE_MODULE module;
  1046. module.skipped = true;
  1047. m_Modules.Insert( filename, module );
  1048. skippedfiles++;
  1049. return;
  1050. }
  1051. if ( !LoadFile( &buffer, filename, module, forcequiet, depth, filelength, numheaders, skippedfiles,
  1052. srcroot, root, baseroot ) )
  1053. {
  1054. CODE_MODULE module;
  1055. module.skipped = true;
  1056. m_Modules.Insert( filename, module );
  1057. skippedfiles++;
  1058. return;
  1059. }
  1060. Assert( buffer );
  1061. m_nBytesProcessed += filelength;
  1062. CODE_MODULE m;
  1063. m.skipped = false;
  1064. m_Modules.Insert( filename, m );
  1065. if ( !forcequiet )
  1066. {
  1067. strcpy( m_szCurrentCPP, filename );
  1068. }
  1069. AddHeader( depth, filename, m_szCurrentCPP );
  1070. bool onclient = !strnicmp( m_szBaseEntityClass, "C_", 2 ) ? true : false;
  1071. // Parse tokens looking for #include directives or class starts
  1072. char *current = buffer;
  1073. current = CC_ParseToken( current );
  1074. while ( 1 )
  1075. {
  1076. // No more tokens
  1077. if ( !current )
  1078. break;
  1079. if ( !stricmp( com_token, "#include" ) )
  1080. {
  1081. current = CC_ParseToken( current );
  1082. if ( strlen( com_token ) > 0 &&
  1083. com_token[ 0 ] != '<' )
  1084. {
  1085. //vprint( "#include %s\n", com_token );
  1086. m_nHeadersProcessed++;
  1087. numheaders++;
  1088. ProcessModule( true, depth + 1, maxdepth, numheaders, skippedfiles, srcroot, baseroot, root, com_token );
  1089. }
  1090. }
  1091. else if ( !stricmp( com_token, "class" ) ||
  1092. !stricmp( com_token, "struct" ) )
  1093. {
  1094. current = CC_ParseToken( current );
  1095. if ( strlen( com_token ) > 0 )
  1096. {
  1097. //vprint( depth, "class %s\n", com_token );
  1098. CClass *cl = AddClass( com_token );
  1099. // Now see if there's a base class
  1100. current = CC_ParseToken( current );
  1101. if ( !stricmp( com_token, ":" ) )
  1102. {
  1103. // Parse out public and then classname an
  1104. current = CC_ParseToken( current );
  1105. if ( !stricmp( com_token, "public" ) )
  1106. {
  1107. current = CC_ParseToken( current );
  1108. if ( strlen( com_token ) > 0 )
  1109. {
  1110. cl->SetBaseClass( com_token );
  1111. do
  1112. {
  1113. current = CC_ParseToken( current );
  1114. } while ( strlen( com_token ) && stricmp( com_token, "{" ) );
  1115. if ( !stricmp( com_token, "{" ) )
  1116. {
  1117. current = cl->ParseClassDeclaration( current );
  1118. }
  1119. }
  1120. }
  1121. }
  1122. else if ( !stricmp( com_token, "{" ) )
  1123. {
  1124. current = cl->ParseClassDeclaration( current );
  1125. }
  1126. }
  1127. }
  1128. else if ( !strnicmp( com_token, "PREDICTABLE_CLASS", strlen( "PREDICTABLE_CLASS" ) ) )
  1129. {
  1130. char prefix[ 32 ];
  1131. prefix[ 0 ] = 0;
  1132. int type = 0;
  1133. int bases = 1;
  1134. int usebase = 0;
  1135. if ( !stricmp( com_token, "PREDICTABLE_CLASS_ALIASED" ) )
  1136. {
  1137. type = 2;
  1138. bases = 2;
  1139. if ( onclient )
  1140. {
  1141. strcpy( prefix, "C_" );
  1142. }
  1143. else
  1144. {
  1145. strcpy( prefix, "C" );
  1146. usebase = 1;
  1147. }
  1148. }
  1149. else if ( !stricmp( com_token, "PREDICTABLE_CLASS_SHARED" ) )
  1150. {
  1151. type = 1;
  1152. bases = 1;
  1153. }
  1154. else if ( !stricmp( com_token, "PREDICTABLE_CLASS" ) )
  1155. {
  1156. type = 0;
  1157. bases = 1;
  1158. if ( onclient )
  1159. {
  1160. strcpy( prefix, "C_" );
  1161. }
  1162. else
  1163. {
  1164. strcpy( prefix, "C" );
  1165. }
  1166. }
  1167. else if ( !stricmp( com_token, "PREDICTABLE_CLASS_ALIASED_PREFIXED" ) )
  1168. {
  1169. // Nothing
  1170. }
  1171. else
  1172. {
  1173. vprint( 0, "PREDICTABLE_CLASS of unknown type!!! %s\n", com_token );
  1174. }
  1175. // parse the (
  1176. current = CC_ParseToken( current );
  1177. if ( !strcmp( com_token, "(" ) )
  1178. {
  1179. // Now the classname
  1180. current = CC_ParseToken( current );
  1181. if ( strlen( com_token ) > 0 )
  1182. {
  1183. //vprint( depth, "class %s\n", com_token );
  1184. CClass *cl = AddClass( com_token );
  1185. // Now see if there's a base class
  1186. current = CC_ParseToken( current );
  1187. if ( !stricmp( com_token, "," ) )
  1188. {
  1189. // Parse out public and then classname an
  1190. current = CC_ParseToken( current );
  1191. if ( strlen( com_token ) > 0 )
  1192. {
  1193. char basename[ 256 ];
  1194. sprintf( basename, "%s%s", prefix, com_token );
  1195. bool valid = true;
  1196. if ( bases == 2 )
  1197. {
  1198. valid = false;
  1199. current = CC_ParseToken( current );
  1200. if ( !stricmp( com_token, "," ) )
  1201. {
  1202. current = CC_ParseToken( current );
  1203. if ( strlen( com_token ) > 0 )
  1204. {
  1205. valid = true;
  1206. if ( usebase == 1 )
  1207. {
  1208. sprintf( basename, "%s%s", prefix, com_token );
  1209. }
  1210. }
  1211. }
  1212. }
  1213. if ( valid )
  1214. {
  1215. cl->SetBaseClass( basename );
  1216. strcpy( cl->m_szTypedefBaseClass, basename );
  1217. }
  1218. do
  1219. {
  1220. current = CC_ParseToken( current );
  1221. } while ( strlen( com_token ) && stricmp( com_token, ")" ) );
  1222. if ( !stricmp( com_token, ")" ) )
  1223. {
  1224. current = cl->ParseClassDeclaration( current );
  1225. }
  1226. }
  1227. }
  1228. else if ( !stricmp( com_token, ")" ) )
  1229. {
  1230. current = cl->ParseClassDeclaration( current );
  1231. }
  1232. }
  1233. }
  1234. }
  1235. else if ( !strcmp( com_token, "TYPEDESCRIPTION" ) ||
  1236. !strcmp( com_token, "typedescription_t" ) )
  1237. {
  1238. current = ParseTypeDescription( current, false );
  1239. }
  1240. else if ( !strcmp( com_token, "BEGIN_DATADESC" ) ||
  1241. !strcmp( com_token, "BEGIN_DATADESC_NO_BASE" ) ||
  1242. !strcmp( com_token, "BEGIN_SIMPLE_DATADESC" ) ||
  1243. !strcmp( com_token, "BEGIN_BYTESWAP_DATADESC" ) )
  1244. {
  1245. current = ParseTypeDescription( current, true );
  1246. }
  1247. else if ( !strcmp( com_token, "BEGIN_PREDICTION_DATA" ) ||
  1248. !strcmp( com_token, "BEGIN_EMBEDDED_PREDDESC" ) )
  1249. {
  1250. current = ParsePredictionTypeDescription( current );
  1251. }
  1252. else if ( !strcmp( com_token, "BEGIN_RECV_TABLE" ) ||
  1253. !strcmp( com_token, "BEGIN_RECV_TABLE_NOBASE" ) ||
  1254. !strcmp( com_token, "IMPLEMENT_CLIENTCLASS_DT" ) ||
  1255. !strcmp( com_token, "IMPLEMENT_CLIENTCLASS_DT_NOBASE" ) )
  1256. {
  1257. current = ParseReceiveTable( current );
  1258. }
  1259. else if ( !strcmp( com_token, "IMPLEMENT_PREDICTABLE_NODATA" ) )
  1260. {
  1261. current = CC_ParseToken( current );
  1262. if ( !strcmp( com_token, "(" ) )
  1263. {
  1264. current = CC_ParseToken( current );
  1265. CClass *cl = FindClass( com_token );
  1266. if ( cl )
  1267. {
  1268. if ( cl->m_bHasPredictionData )
  1269. {
  1270. if ( !forcequiet )
  1271. {
  1272. vprint( 0, "Class %s declared predictable and implemented with IMPLEMENT_PREDICTABLE_NODATA in typedescription\n",
  1273. cl->m_szName );
  1274. }
  1275. cl->m_bHasPredictionData = false;
  1276. }
  1277. }
  1278. current = CC_ParseToken( current );
  1279. }
  1280. }
  1281. current = CC_ParseToken( current );
  1282. }
  1283. COM_FreeFile( (unsigned char *)buffer );
  1284. if ( !forcequiet && !GetQuiet() )
  1285. {
  1286. vprint( 0, " %s: headers (%i game / %i total)", (char *)&filename[ m_nOffset ], numheaders - skippedfiles, numheaders );
  1287. if ( maxdepth > 1 )
  1288. {
  1289. vprint( 0, ", depth %i", maxdepth );
  1290. }
  1291. vprint( 0, "\n" );
  1292. }
  1293. m_nLinesOfCode += linesprocessed;
  1294. linesprocessed = 0;
  1295. }
  1296. void CCodeProcessor::ProcessModules( const char *srcroot, const char *root, const char *rootmodule )
  1297. {
  1298. m_nFilesProcessed++;
  1299. // Reset header list per module
  1300. m_Headers.RemoveAll();
  1301. int numheaders = 0;
  1302. int maxdepth = 0;
  1303. int skippedfiles = 0;
  1304. ProcessModule( false, 0, maxdepth, numheaders, skippedfiles, srcroot, root, root, rootmodule );
  1305. }
  1306. void ReportMissingTypes();
  1307. void CCodeProcessor::PrintResults( const char *baseentityclass )
  1308. {
  1309. vprint( 0, "\nChecking for errors and totaling...\n\n" );
  1310. ResolveBaseClasses( baseentityclass );
  1311. PrintClassList();
  1312. PrintMissingTDFields();
  1313. ReportMissingTypes();
  1314. ReportHungarianNotationErrors();
  1315. vprint( 0, "%i total classes parsed from %i files ( %i headers parsed )\n",
  1316. m_nClassesParsed,
  1317. m_nFilesProcessed,
  1318. m_nHeadersProcessed );
  1319. vprint( 0, "%.3f K lines of code processed\n",
  1320. (double)m_nLinesOfCode / 1024.0 );
  1321. double elapsed = ( m_flEnd - m_flStart );
  1322. if ( elapsed > 0.0 )
  1323. {
  1324. vprint( 0, "%.2f K processed in %.3f seconds, throughput %.2f KB/sec\n\n",
  1325. (double)m_nBytesProcessed / 1024.0, elapsed, (double)m_nBytesProcessed / ( 1024.0 * elapsed ) );
  1326. }
  1327. Clear();
  1328. }
  1329. CCodeProcessor::CCodeProcessor( void )
  1330. {
  1331. m_pClassList = NULL;
  1332. m_Modules.RemoveAll();
  1333. m_bQuiet = false;
  1334. m_bPrintHierarchy = false;
  1335. m_bPrintMembers = true;
  1336. m_bPrintTypedescriptionErrors = true;
  1337. m_bPrintPredictionDescErrors = true;
  1338. m_bCreateMissingTDs = false;
  1339. m_bLogToFile = false;
  1340. m_bCheckHungarian = false;
  1341. m_nFilesProcessed = 0;
  1342. m_nHeadersProcessed = 0;
  1343. m_nClassesParsed = 0;
  1344. m_nOffset = 0;
  1345. m_nBytesProcessed = 0;
  1346. m_nLinesOfCode = 0;
  1347. m_flStart = 0.0;
  1348. m_flEnd = 0.0;
  1349. m_szCurrentCPP[ 0 ] = 0;
  1350. m_szBaseEntityClass[ 0 ] = 0;
  1351. }
  1352. CCodeProcessor::~CCodeProcessor( void )
  1353. {
  1354. }
  1355. void CCodeProcessor::ConstructModuleList_R( int level, const char *baseentityclass,
  1356. const char *gamespecific, const char *root, const char *srcroot )
  1357. {
  1358. char directory[ 256 ];
  1359. char filename[ 256 ];
  1360. WIN32_FIND_DATA wfd;
  1361. HANDLE ff;
  1362. sprintf( directory, "%s\\*.*", root );
  1363. if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
  1364. return;
  1365. do
  1366. {
  1367. if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  1368. {
  1369. if ( wfd.cFileName[ 0 ] == '.' )
  1370. continue;
  1371. // Once we descend down a branch, don't keep looking for hl2/tf2 in name, just recurse through all children
  1372. if ( level == 0 && !strstr( wfd.cFileName, gamespecific ) )
  1373. continue;
  1374. // Recurse down directory
  1375. sprintf( filename, "%s\\%s", root, wfd.cFileName );
  1376. ConstructModuleList_R( level+1, baseentityclass, gamespecific, filename, srcroot );
  1377. }
  1378. else
  1379. {
  1380. if ( strstr( wfd.cFileName, ".cpp" ) )
  1381. {
  1382. ProcessModules( srcroot, root, wfd.cFileName );
  1383. }
  1384. }
  1385. } while ( FindNextFile( ff, &wfd ) );
  1386. }
  1387. void CCodeProcessor::CleanupIncludePath()
  1388. {
  1389. for ( int i = m_IncludePath.Count(); --i >= 0; )
  1390. {
  1391. delete [] m_IncludePath[i];
  1392. }
  1393. m_IncludePath.RemoveAll();
  1394. }
  1395. void CCodeProcessor::AddIncludePath( const char *pPath )
  1396. {
  1397. int i = m_IncludePath.AddToTail();
  1398. int nLen = strlen(pPath) + 1;
  1399. m_IncludePath[i] = new char[nLen];
  1400. memcpy( m_IncludePath[i], pPath, nLen );
  1401. }
  1402. void CCodeProcessor::SetupIncludePath( const char *sourcetreebase, const char *subdir, const char *gamespecific )
  1403. {
  1404. CleanupIncludePath();
  1405. char path[MAX_PATH];
  1406. sprintf( path, "%s\\%s", sourcetreebase, subdir );
  1407. strlwr( path );
  1408. AddIncludePath( path );
  1409. char modsubdir[128];
  1410. if ( !stricmp(subdir, "dlls") )
  1411. {
  1412. sprintf(modsubdir,"%s\\%s_dll", subdir, gamespecific );
  1413. }
  1414. else if ( !stricmp(subdir, "cl_dll") )
  1415. {
  1416. sprintf(modsubdir,"%s\\%s_hud", subdir, gamespecific );
  1417. }
  1418. else
  1419. {
  1420. sprintf(modsubdir,"%s\\%s", subdir, gamespecific );
  1421. }
  1422. sprintf( path, "%s\\%s", sourcetreebase, modsubdir );
  1423. strlwr( path );
  1424. AddIncludePath( path );
  1425. // Game shared
  1426. sprintf( path, "%s\\game_shared", sourcetreebase );
  1427. strlwr( path );
  1428. AddIncludePath( path );
  1429. sprintf( path, "%s\\game_shared\\%s", sourcetreebase, gamespecific );
  1430. strlwr( path );
  1431. AddIncludePath( path );
  1432. sprintf( path, "%s\\public", sourcetreebase );
  1433. strlwr( path );
  1434. AddIncludePath( path );
  1435. }
  1436. void CCodeProcessor::Process( const char *baseentityclass, const char *gamespecific, const char *sourcetreebase, const char *subdir )
  1437. {
  1438. SetupIncludePath( sourcetreebase, subdir, gamespecific );
  1439. strcpy( m_szBaseEntityClass, baseentityclass );
  1440. m_nBytesProcessed = 0;
  1441. m_nFilesProcessed = 0;
  1442. m_nHeadersProcessed = 0;
  1443. m_nClassesParsed = 0;
  1444. m_nLinesOfCode = 0;
  1445. linesprocessed = 0;
  1446. m_Modules.RemoveAll();
  1447. m_Headers.RemoveAll();
  1448. m_flStart = UTIL_FloatTime();
  1449. char rootdirectory[ 256 ];
  1450. sprintf( rootdirectory, "%s\\%s", sourcetreebase, subdir );
  1451. vprint( 0, "--- Processing %s\n\n", rootdirectory );
  1452. m_nOffset = strlen( rootdirectory ) + 1;
  1453. ConstructModuleList_R( 0, baseentityclass, gamespecific, rootdirectory, sourcetreebase );
  1454. sprintf( rootdirectory, "%s\\%s", sourcetreebase, "game_shared" );
  1455. vprint( 0, "--- Processing %s\n\n", rootdirectory );
  1456. m_nOffset = strlen( rootdirectory ) + 1;
  1457. ConstructModuleList_R( 0, baseentityclass, gamespecific, rootdirectory, sourcetreebase );
  1458. m_flEnd = UTIL_FloatTime();
  1459. PrintResults( baseentityclass );
  1460. }
  1461. void CCodeProcessor::Process( const char *baseentityclass, const char *gamespecific,
  1462. const char *sourcetreebase, const char *subdir, const char *pFileName )
  1463. {
  1464. SetupIncludePath( sourcetreebase, subdir, gamespecific );
  1465. strcpy( m_szBaseEntityClass, baseentityclass );
  1466. m_nBytesProcessed = 0;
  1467. m_nFilesProcessed = 0;
  1468. m_nHeadersProcessed = 0;
  1469. m_nClassesParsed = 0;
  1470. m_nLinesOfCode = 0;
  1471. linesprocessed = 0;
  1472. m_Modules.RemoveAll();
  1473. m_Headers.RemoveAll();
  1474. m_flStart = UTIL_FloatTime();
  1475. char rootdirectory[ 256 ];
  1476. sprintf( rootdirectory, "%s\\%s", sourcetreebase, subdir );
  1477. vprint( 0, "--- Processing %s\n\n", rootdirectory );
  1478. m_nOffset = strlen( rootdirectory ) + 1;
  1479. ProcessModules( sourcetreebase, rootdirectory, pFileName );
  1480. m_flEnd = UTIL_FloatTime();
  1481. PrintResults( baseentityclass );
  1482. }
  1483. void CCodeProcessor::SetQuiet( bool quiet )
  1484. {
  1485. m_bQuiet = quiet;
  1486. }
  1487. bool CCodeProcessor::GetQuiet( void ) const
  1488. {
  1489. return m_bQuiet;
  1490. }
  1491. void CCodeProcessor::SetPrintHierarchy( bool print )
  1492. {
  1493. m_bPrintHierarchy = print;
  1494. }
  1495. bool CCodeProcessor::GetPrintHierarchy( void ) const
  1496. {
  1497. return m_bPrintHierarchy;
  1498. }
  1499. void CCodeProcessor::SetPrintMembers( bool print )
  1500. {
  1501. m_bPrintMembers = print;
  1502. }
  1503. bool CCodeProcessor::GetPrintMembers( void ) const
  1504. {
  1505. return m_bPrintMembers;
  1506. }
  1507. void CCodeProcessor::SetPrintTDs( bool print )
  1508. {
  1509. m_bPrintTypedescriptionErrors = print;
  1510. }
  1511. bool CCodeProcessor::GetPrintTDs( void ) const
  1512. {
  1513. return m_bPrintTypedescriptionErrors;
  1514. }
  1515. void CCodeProcessor::SetLogFile( bool log )
  1516. {
  1517. m_bLogToFile = log;
  1518. }
  1519. bool CCodeProcessor::GetLogFile( void ) const
  1520. {
  1521. return m_bLogToFile;
  1522. }
  1523. void CCodeProcessor::SetPrintPredTDs( bool print )
  1524. {
  1525. m_bPrintPredictionDescErrors = print;
  1526. }
  1527. bool CCodeProcessor::GetPrintPredTDs( void ) const
  1528. {
  1529. return m_bPrintPredictionDescErrors;
  1530. }
  1531. void CCodeProcessor::SetPrintCreateMissingTDs( bool print )
  1532. {
  1533. m_bCreateMissingTDs = print;
  1534. }
  1535. bool CCodeProcessor::GetPrintCreateMissingTDs( void ) const
  1536. {
  1537. return m_bCreateMissingTDs;
  1538. }
  1539. void CCodeProcessor::SetPrintCreateMissingPredTDs( bool print )
  1540. {
  1541. m_bCreateMissingPredTDs = print;
  1542. }
  1543. bool CCodeProcessor::GetPrintCreateMissingPredTDs( void ) const
  1544. {
  1545. return m_bCreateMissingPredTDs;
  1546. }
  1547. void CCodeProcessor::SetCheckHungarian( bool check )
  1548. {
  1549. m_bCheckHungarian = check;
  1550. }
  1551. bool CCodeProcessor::GetCheckHungarian() const
  1552. {
  1553. return m_bCheckHungarian;
  1554. }
  1555. static CCodeProcessor g_Processor;
  1556. ICodeProcessor *processor = ( ICodeProcessor * )&g_Processor;