Counter Strike : Global Offensive Source Code
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.

1427 lines
36 KiB

  1. //====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <stdio.h>
  9. #include <io.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13. #include <time.h>
  14. #include <stdarg.h>
  15. #include "tier0/platform.h"
  16. #include "tier0/dbg.h"
  17. #include "tier1/utlbuffer.h"
  18. #include "cfgprocessor.h"
  19. extern bool g_bIsPS3;
  20. // Type conversions should be controlled by programmer explicitly - shadercompile makes use of 64-bit integer arithmetics
  21. #pragma warning( error : 4244 )
  22. namespace
  23. {
  24. int Usage()
  25. {
  26. printf( "Usage: expparser [OPTIONS] <input.txt 2>>output.txt\n" );
  27. printf( "Options: [none]\n" );
  28. printf( "Input: Sections in a file:\n" );
  29. printf( " #BEGIN\n" );
  30. printf( " #DEFINES:\n" );
  31. printf( " FASTPATH=0..2\n" );
  32. printf( " FOGTYPE=0..5\n" );
  33. printf( " #SKIP:\n" );
  34. printf( " ($FOGTYPE > 1) && (!$FASTPATH)\n" );
  35. printf( " #COMMAND:\n" );
  36. printf( " fxc.exe /DFLAGS=0x00\n" );
  37. printf( " /Foshader.o myshader.fxc > output.txt\n" );
  38. printf( " #END\n" );
  39. printf( "Version: expparser compiled on " __DATE__ " @ " __TIME__ ".\n" );
  40. return -1;
  41. }
  42. };
  43. namespace
  44. {
  45. static bool s_bNoOutput = true;
  46. void OutputF( FILE *f, char const *szFmt, ... )
  47. {
  48. if( s_bNoOutput )
  49. return;
  50. va_list args;
  51. va_start( args, szFmt );
  52. vfprintf( f, szFmt, args );
  53. va_end( args );
  54. }
  55. };
  56. //////////////////////////////////////////////////////////////////////////
  57. //
  58. // Utility classes:
  59. // QuickArray<T>
  60. // QuickStrIdx
  61. // QuickString
  62. // QuickStrUnique
  63. // QuickMap
  64. //
  65. //////////////////////////////////////////////////////////////////////////
  66. #define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
  67. #include <hash_map>
  68. #include <map>
  69. #include <set>
  70. #include <vector>
  71. #include <string>
  72. #include <algorithm>
  73. template < typename T >
  74. class QuickArray : private std::vector < T >
  75. {
  76. public:
  77. void Append( T const &e ) { push_back( e ); };
  78. int Size( void ) const { return ( int ) size(); };
  79. T const & Get( int idx ) const { return at( idx ); };
  80. T & GetForEdit( int idx ) { return at( idx ); }
  81. void Clear( void ) { clear(); }
  82. T const * ArrayBase() const { return empty() ? NULL : &at( 0 ); }
  83. T * ArrayBaseForEdit() { return empty() ? NULL : &at( 0 ); }
  84. };
  85. template < typename T >
  86. class QuickStack : private std::vector < T >
  87. {
  88. public:
  89. void Push( T const &e ) { push_back( e ); };
  90. int Size( void ) const { return ( int ) size(); };
  91. T const & Top( void ) const { return at( Size() - 1 ); };
  92. void Pop( void ) { pop_back(); }
  93. void Clear( void ) { clear(); }
  94. };
  95. template < typename K, typename V >
  96. class QuickMap : private std::map < K, V >
  97. {
  98. public:
  99. void Append( K const &k, V const &v ) { insert( value_type( k, v ) ); };
  100. int Size( void ) const { return ( int ) size(); };
  101. V const & GetLessOrEq( K &k, V const &v ) const;
  102. V const & Get( K const &k, V const &v ) const { const_iterator it = find( k ); return ( it != end() ? it->second : v ); };
  103. V & GetForEdit( K const &k, V &v ) { iterator it = find( k ); return ( it != end() ? it->second : v ); };
  104. void Clear( void ) { clear(); }
  105. };
  106. template < typename K, typename V >
  107. V const & QuickMap< K, V >::GetLessOrEq( K &k, V const &v ) const
  108. {
  109. const_iterator it = lower_bound( k );
  110. if ( end() == it )
  111. {
  112. if ( empty() )
  113. return v;
  114. -- it;
  115. }
  116. if ( k < it->first )
  117. {
  118. if ( begin() == it )
  119. return v;
  120. -- it;
  121. }
  122. k = it->first;
  123. return it->second;
  124. }
  125. class QuickStrIdx : private stdext::hash_map < std::string, int >
  126. {
  127. public:
  128. void Append( char const *szName, int idx ) { insert( value_type( szName, idx ) ); };
  129. int Size( void ) const { return ( int ) size(); };
  130. int Get( char const *szName ) const { const_iterator it = find( szName ); if ( end() != it ) return it->second; else return -1; };
  131. void Clear( void ) { clear(); }
  132. };
  133. class QuickStrUnique : private std::set < std::string >
  134. {
  135. public:
  136. int Size( void ) const { return ( int ) size(); }
  137. bool Add( char const *szString ) { return insert( szString ).second; }
  138. void Remove( char const *szString ) { erase( szString ); }
  139. char const * Lookup( char const *szString ) { const_iterator it = find( szString ); if ( end() != it ) return it->data(); else return NULL; }
  140. char const * AddLookup( char const *szString ) { iterator it = insert( szString ).first; if ( end() != it ) return it->data(); else return NULL; }
  141. void Clear( void ) { clear(); }
  142. };
  143. class QuickString : private std::vector< char >
  144. {
  145. public:
  146. explicit QuickString( char const *szValue, size_t len = -1 );
  147. int Size() const { return ( int ) ( size() - 1 ); }
  148. char * Get() { return &at( 0 ); }
  149. };
  150. QuickString::QuickString( char const *szValue, size_t len )
  151. {
  152. if ( size_t( -1 ) == len )
  153. len = ( size_t ) strlen( szValue );
  154. resize( len + 1, 0 );
  155. memcpy( Get(), szValue, len );
  156. }
  157. //////////////////////////////////////////////////////////////////////////
  158. //
  159. // Define class
  160. //
  161. //////////////////////////////////////////////////////////////////////////
  162. class Define
  163. {
  164. public:
  165. explicit Define( char const *szName, int min, int max, bool bStatic ) : m_sName( szName ), m_min( min ), m_max( max ), m_bStatic( bStatic ) {}
  166. public:
  167. char const * Name() const { return m_sName.data(); };
  168. int Min() const { return m_min; };
  169. int Max() const { return m_max; };
  170. bool IsStatic() const { return m_bStatic; }
  171. protected:
  172. std::string m_sName;
  173. int m_min, m_max;
  174. bool m_bStatic;
  175. };
  176. //////////////////////////////////////////////////////////////////////////
  177. //
  178. // Expression parser
  179. //
  180. //////////////////////////////////////////////////////////////////////////
  181. class IEvaluationContext
  182. {
  183. public:
  184. virtual int GetVariableValue( int nSlot ) = 0;
  185. virtual char const * GetVariableName( int nSlot ) = 0;
  186. virtual int GetVariableSlot( char const *szVariableName ) = 0;
  187. };
  188. class IExpression
  189. {
  190. public:
  191. virtual int Evaluate( IEvaluationContext *pCtx ) const = 0;
  192. virtual void Print( IEvaluationContext *pCtx ) const = 0;
  193. };
  194. #define EVAL virtual int Evaluate( IEvaluationContext *pCtx ) const
  195. #define PRNT virtual void Print( IEvaluationContext *pCtx ) const
  196. class CExprConstant : public IExpression
  197. {
  198. public:
  199. CExprConstant( int value ) : m_value( value ) {}
  200. EVAL { pCtx; return m_value; };
  201. PRNT { pCtx; OutputF( stdout, "%d", m_value ); }
  202. public:
  203. int m_value;
  204. };
  205. class CExprVariable : public IExpression
  206. {
  207. public:
  208. CExprVariable( int nSlot ) : m_nSlot( nSlot ) {}
  209. EVAL { return (m_nSlot >= 0) ? pCtx->GetVariableValue( m_nSlot ) : 0; };
  210. PRNT { (m_nSlot >= 0) ? OutputF( stdout, "$%s", pCtx->GetVariableName( m_nSlot ) ) : OutputF( stdout, "$**@**" ); }
  211. public:
  212. int m_nSlot;
  213. };
  214. class CExprUnary : public IExpression
  215. {
  216. public:
  217. CExprUnary( IExpression *x ) : m_x( x ) {}
  218. public:
  219. IExpression *m_x;
  220. };
  221. #define BEGIN_EXPR_UNARY( className ) class className : public CExprUnary { public: className( IExpression *x ) : CExprUnary( x ) {}
  222. #define END_EXPR_UNARY() };
  223. BEGIN_EXPR_UNARY( CExprUnary_Negate )
  224. EVAL { return ! m_x->Evaluate( pCtx ); };
  225. PRNT { OutputF( stdout, "!" ); m_x->Print(pCtx); }
  226. END_EXPR_UNARY()
  227. class CExprBinary : public IExpression
  228. {
  229. public:
  230. CExprBinary( IExpression *x, IExpression *y ) : m_x( x ), m_y( y ) {}
  231. virtual int Priority() const = 0;
  232. public:
  233. IExpression *m_x;
  234. IExpression *m_y;
  235. };
  236. #define BEGIN_EXPR_BINARY( className ) class className : public CExprBinary { public: className( IExpression *x, IExpression *y ) : CExprBinary( x, y ) {}
  237. #define EXPR_BINARY_PRIORITY( nPriority ) virtual int Priority() const { return nPriority; };
  238. #define END_EXPR_BINARY() };
  239. BEGIN_EXPR_BINARY( CExprBinary_And )
  240. EVAL { return m_x->Evaluate( pCtx ) && m_y->Evaluate( pCtx ); }
  241. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " && " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  242. EXPR_BINARY_PRIORITY( 1 );
  243. END_EXPR_BINARY()
  244. BEGIN_EXPR_BINARY( CExprBinary_Or )
  245. EVAL { return m_x->Evaluate( pCtx ) || m_y->Evaluate( pCtx ); }
  246. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " || " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  247. EXPR_BINARY_PRIORITY( 2 );
  248. END_EXPR_BINARY()
  249. BEGIN_EXPR_BINARY( CExprBinary_Eq )
  250. EVAL { return m_x->Evaluate( pCtx ) == m_y->Evaluate( pCtx ); }
  251. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " == " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  252. EXPR_BINARY_PRIORITY( 0 );
  253. END_EXPR_BINARY()
  254. BEGIN_EXPR_BINARY( CExprBinary_Neq )
  255. EVAL { return m_x->Evaluate( pCtx ) != m_y->Evaluate( pCtx ); }
  256. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " != " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  257. EXPR_BINARY_PRIORITY( 0 );
  258. END_EXPR_BINARY()
  259. BEGIN_EXPR_BINARY( CExprBinary_G )
  260. EVAL { return m_x->Evaluate( pCtx ) > m_y->Evaluate( pCtx ); }
  261. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " > " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  262. EXPR_BINARY_PRIORITY( 0 );
  263. END_EXPR_BINARY()
  264. BEGIN_EXPR_BINARY( CExprBinary_Ge )
  265. EVAL { return m_x->Evaluate( pCtx ) >= m_y->Evaluate( pCtx ); }
  266. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " >= " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  267. EXPR_BINARY_PRIORITY( 0 );
  268. END_EXPR_BINARY()
  269. BEGIN_EXPR_BINARY( CExprBinary_L )
  270. EVAL { return m_x->Evaluate( pCtx ) < m_y->Evaluate( pCtx ); }
  271. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " < " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  272. EXPR_BINARY_PRIORITY( 0 );
  273. END_EXPR_BINARY()
  274. BEGIN_EXPR_BINARY( CExprBinary_Le )
  275. EVAL { return m_x->Evaluate( pCtx ) <= m_y->Evaluate( pCtx ); }
  276. PRNT { OutputF( stdout, "( " ); m_x->Print( pCtx ); OutputF( stdout, " <= " ); m_y->Print( pCtx ); OutputF( stdout, " )" ); }
  277. EXPR_BINARY_PRIORITY( 0 );
  278. END_EXPR_BINARY()
  279. class CComplexExpression : public IExpression
  280. {
  281. public:
  282. CComplexExpression( IEvaluationContext *pCtx ) : m_pRoot( NULL ), m_pContext( pCtx ) { }
  283. ~CComplexExpression() { Clear(); }
  284. void Parse( char const *szExpression );
  285. void Clear( void );
  286. public:
  287. EVAL { return m_pRoot ? m_pRoot->Evaluate( pCtx ? pCtx : m_pContext ) : 0; };
  288. PRNT { OutputF( stdout, "[ " ); m_pRoot ? m_pRoot->Print( pCtx ? pCtx : m_pContext ) : OutputF( stdout, "**NEXPR**" ); OutputF( stdout, " ]\n" ); }
  289. protected:
  290. IExpression * ParseTopLevel( char *&szExpression );
  291. IExpression * ParseInternal( char *&szExpression );
  292. IExpression * Allocated( IExpression *pExpression );
  293. IExpression * AbortedParse( char *&szExpression ) const { *szExpression = 0; return m_pDefFalse; }
  294. protected:
  295. QuickArray < IExpression * > m_arrAllExpressions;
  296. IExpression *m_pRoot;
  297. IEvaluationContext *m_pContext;
  298. IExpression *m_pDefTrue, *m_pDefFalse;
  299. };
  300. void CComplexExpression::Parse( char const *szExpressionIn )
  301. {
  302. Clear();
  303. m_pDefTrue = Allocated( new CExprConstant( 1 ) );
  304. m_pDefFalse = Allocated( new CExprConstant( 0 ) );
  305. m_pRoot = m_pDefFalse;
  306. if ( szExpressionIn )
  307. {
  308. QuickString qs( szExpressionIn );
  309. char *szExpression = qs.Get();
  310. char *szExpectEnd = szExpression + qs.Size();
  311. char *szParse = szExpression;
  312. m_pRoot = ParseTopLevel( szParse );
  313. if ( szParse != szExpectEnd )
  314. {
  315. m_pRoot = m_pDefFalse;
  316. }
  317. }
  318. }
  319. IExpression * CComplexExpression::ParseTopLevel( char *&szExpression )
  320. {
  321. QuickStack< CExprBinary * > exprStack;
  322. IExpression *pFirstToken = ParseInternal( szExpression );
  323. for ( ; ; )
  324. {
  325. // Skip whitespace
  326. while ( *szExpression && V_isspace( *szExpression ) )
  327. {
  328. ++ szExpression;
  329. }
  330. // End of binary expression
  331. if ( !*szExpression || ( *szExpression == ')' ) )
  332. {
  333. break;
  334. }
  335. // Determine the binary expression type
  336. CExprBinary *pBinaryExpression = NULL;
  337. if ( 0 )
  338. {
  339. NULL;
  340. }
  341. else if ( !strncmp( szExpression, "&&", 2 ) )
  342. {
  343. pBinaryExpression = new CExprBinary_And( NULL, NULL );
  344. szExpression += 2;
  345. }
  346. else if ( !strncmp( szExpression, "||", 2 ) )
  347. {
  348. pBinaryExpression = new CExprBinary_Or( NULL, NULL );
  349. szExpression += 2;
  350. }
  351. else if ( !strncmp( szExpression, ">=", 2 ) )
  352. {
  353. pBinaryExpression = new CExprBinary_Ge( NULL, NULL );
  354. szExpression += 2;
  355. }
  356. else if ( !strncmp( szExpression, "<=", 2 ) )
  357. {
  358. pBinaryExpression = new CExprBinary_Le( NULL, NULL );
  359. szExpression += 2;
  360. }
  361. else if ( !strncmp( szExpression, "==", 2 ) )
  362. {
  363. pBinaryExpression = new CExprBinary_Eq( NULL, NULL );
  364. szExpression += 2;
  365. }
  366. else if ( !strncmp( szExpression, "!=", 2 ) )
  367. {
  368. pBinaryExpression = new CExprBinary_Neq( NULL, NULL );
  369. szExpression += 2;
  370. }
  371. else if ( *szExpression == '>' )
  372. {
  373. pBinaryExpression = new CExprBinary_G( NULL, NULL );
  374. ++ szExpression;
  375. }
  376. else if ( *szExpression == '<' )
  377. {
  378. pBinaryExpression = new CExprBinary_L( NULL, NULL );
  379. ++ szExpression;
  380. }
  381. else
  382. {
  383. return AbortedParse( szExpression );
  384. }
  385. Allocated( pBinaryExpression );
  386. pBinaryExpression->m_y = ParseInternal( szExpression );
  387. // Figure out the expression priority
  388. int nPriority = pBinaryExpression->Priority();
  389. IExpression *pLastExpr = pFirstToken;
  390. while ( exprStack.Size() )
  391. {
  392. CExprBinary *pStickTo = exprStack.Top();
  393. pLastExpr = pStickTo;
  394. if ( nPriority > pStickTo->Priority() )
  395. exprStack.Pop();
  396. else
  397. break;
  398. }
  399. if ( exprStack.Size() )
  400. {
  401. CExprBinary *pStickTo = exprStack.Top();
  402. pBinaryExpression->m_x = pStickTo->m_y;
  403. pStickTo->m_y = pBinaryExpression;
  404. }
  405. else
  406. {
  407. pBinaryExpression->m_x = pLastExpr;
  408. }
  409. exprStack.Push( pBinaryExpression );
  410. }
  411. // Tip-of-the-tree retrieval
  412. {
  413. IExpression *pLastExpr = pFirstToken;
  414. while ( exprStack.Size() )
  415. {
  416. pLastExpr = exprStack.Top();
  417. exprStack.Pop();
  418. }
  419. return pLastExpr;
  420. }
  421. }
  422. IExpression * CComplexExpression::ParseInternal( char *&szExpression )
  423. {
  424. // Skip whitespace
  425. while ( *szExpression && V_isspace( *szExpression ) )
  426. {
  427. ++ szExpression;
  428. }
  429. if ( !*szExpression )
  430. return AbortedParse( szExpression );
  431. if ( 0 )
  432. {
  433. NULL;
  434. }
  435. else if ( V_isdigit( *szExpression ) )
  436. {
  437. long lValue = strtol( szExpression, &szExpression, 10 );
  438. return Allocated( new CExprConstant( lValue ) );
  439. }
  440. else if ( !strncmp( szExpression, "defined", 7 ) )
  441. {
  442. szExpression += 7;
  443. IExpression *pNext = ParseInternal( szExpression );
  444. return Allocated( new CExprConstant( pNext->Evaluate( m_pContext ) ) );
  445. }
  446. else if ( *szExpression == '(' )
  447. {
  448. ++ szExpression;
  449. IExpression *pBracketed = ParseTopLevel( szExpression );
  450. if ( ')' == *szExpression )
  451. {
  452. ++ szExpression;
  453. return pBracketed;
  454. }
  455. else
  456. {
  457. return AbortedParse( szExpression );
  458. }
  459. }
  460. else if ( *szExpression == '$' )
  461. {
  462. size_t lenVariable = 0;
  463. for ( char *szEndVar = szExpression + 1; *szEndVar; ++ szEndVar, ++ lenVariable )
  464. {
  465. if ( !V_isalnum( *szEndVar ) )
  466. {
  467. switch ( *szEndVar )
  468. {
  469. case '_':
  470. break;
  471. default:
  472. goto parsed_variable_name;
  473. }
  474. }
  475. }
  476. parsed_variable_name:
  477. int nSlot = m_pContext->GetVariableSlot( QuickString( szExpression + 1, lenVariable ).Get() );
  478. szExpression += lenVariable + 1;
  479. return Allocated( new CExprVariable( nSlot ) );
  480. }
  481. else if ( *szExpression == '!' )
  482. {
  483. ++ szExpression;
  484. IExpression *pNext = ParseInternal( szExpression );
  485. return Allocated( new CExprUnary_Negate( pNext ) );
  486. }
  487. else
  488. {
  489. return AbortedParse( szExpression );
  490. }
  491. }
  492. IExpression * CComplexExpression::Allocated( IExpression *pExpression )
  493. {
  494. m_arrAllExpressions.Append( pExpression );
  495. return pExpression;
  496. }
  497. void CComplexExpression::Clear( void )
  498. {
  499. for ( int k = 0; k < m_arrAllExpressions.Size() ; ++ k )
  500. {
  501. delete m_arrAllExpressions.Get( k );
  502. }
  503. m_arrAllExpressions.Clear();
  504. m_pRoot = NULL;
  505. }
  506. #undef BEGIN_EXPR_UNARY
  507. #undef BEGIN_EXPR_BINARY
  508. #undef END_EXPR_UNARY
  509. #undef END_EXPR_BINARY
  510. #undef EVAL
  511. #undef PRNT
  512. //////////////////////////////////////////////////////////////////////////
  513. //
  514. // Combo Generator class
  515. //
  516. //////////////////////////////////////////////////////////////////////////
  517. class ComboGenerator : public IEvaluationContext
  518. {
  519. public:
  520. void AddDefine( Define const &df );
  521. Define const * const GetDefinesBase( void ) { return m_arrDefines.ArrayBase(); }
  522. Define const * const GetDefinesEnd( void ) { return m_arrDefines.ArrayBase() + m_arrDefines.Size(); }
  523. uint64 NumCombos();
  524. uint64 NumCombos( bool bStaticCombos );
  525. void RunAllCombos( CComplexExpression const &skipExpr );
  526. // IEvaluationContext
  527. public:
  528. virtual int GetVariableValue( int nSlot ) { return m_arrVarSlots.Get( nSlot ); };
  529. virtual char const * GetVariableName( int nSlot ) { return m_arrDefines.Get( nSlot ).Name(); };
  530. virtual int GetVariableSlot( char const *szVariableName ) { return m_mapDefines.Get( szVariableName ); };
  531. protected:
  532. QuickArray< Define > m_arrDefines;
  533. QuickStrIdx m_mapDefines;
  534. QuickArray < int > m_arrVarSlots;
  535. };
  536. void ComboGenerator::AddDefine( Define const &df )
  537. {
  538. m_mapDefines.Append( df.Name(), m_arrDefines.Size() );
  539. m_arrDefines.Append( df );
  540. m_arrVarSlots.Append( 1 );
  541. }
  542. uint64 ComboGenerator::NumCombos()
  543. {
  544. uint64 numCombos = 1;
  545. for ( int k = 0, kEnd = m_arrDefines.Size(); k < kEnd; ++ k )
  546. {
  547. Define const &df = m_arrDefines.Get( k );
  548. numCombos *= ( df.Max() - df.Min() + 1 );
  549. }
  550. return numCombos;
  551. }
  552. uint64 ComboGenerator::NumCombos( bool bStaticCombos )
  553. {
  554. uint64 numCombos = 1;
  555. for ( int k = 0, kEnd = m_arrDefines.Size(); k < kEnd; ++ k )
  556. {
  557. Define const &df = m_arrDefines.Get( k );
  558. ( df.IsStatic() == bStaticCombos ) ? numCombos *= ( df.Max() - df.Min() + 1 ) : 0;
  559. }
  560. return numCombos;
  561. }
  562. struct ComboEmission
  563. {
  564. std::string m_sPrefix;
  565. std::string m_sSuffix;
  566. } g_comboEmission;
  567. size_t const g_lenTmpBuffer = 1 * 1024 * 1024; // 1Mb buffer for tmp storage
  568. char g_chTmpBuffer[g_lenTmpBuffer];
  569. void ComboGenerator::RunAllCombos( CComplexExpression const &skipExpr )
  570. {
  571. // Combo numbers
  572. uint64 const nTotalCombos = NumCombos();
  573. // Get the pointers
  574. int * const pnValues = m_arrVarSlots.ArrayBaseForEdit();
  575. int * const pnValuesEnd = pnValues + m_arrVarSlots.Size();
  576. int *pSetValues;
  577. // Defines
  578. Define const * const pDefVars = m_arrDefines.ArrayBase();
  579. Define const *pSetDef;
  580. // Set all the variables to max values
  581. for ( pSetValues = pnValues, pSetDef = pDefVars;
  582. pSetValues < pnValuesEnd;
  583. ++ pSetValues, ++ pSetDef )
  584. {
  585. *pSetValues = pSetDef->Max();
  586. }
  587. // Expressions distributed [0] = skips, [1] = evaluated
  588. uint64 nSkipEvalCounters[2] = { 0, 0 };
  589. // Go ahead and run the iterations
  590. {
  591. uint64 nCurrentCombo = nTotalCombos;
  592. next_combo_iteration:
  593. -- nCurrentCombo;
  594. int const valExprSkip = skipExpr.Evaluate( this );
  595. ++ nSkipEvalCounters[ !valExprSkip ];
  596. if ( valExprSkip )
  597. {
  598. // TECH NOTE: Giving performance hint to compiler to place a jump here
  599. // since there will be much more skips and actually less than 0.8% cases
  600. // will be "OnCombo" hits.
  601. NULL;
  602. }
  603. else
  604. {
  605. // ------- OnCombo( nCurrentCombo ); ----------
  606. OutputF( stderr, "%s ", g_comboEmission.m_sPrefix.data() );
  607. if ( g_bIsPS3 )
  608. {
  609. OutputF( stderr, "-DSHADERCOMBO=%d ", nCurrentCombo );
  610. }
  611. else
  612. {
  613. OutputF( stderr, "/DSHADERCOMBO=%d ", nCurrentCombo );
  614. }
  615. for ( pSetValues = pnValues, pSetDef = pDefVars;
  616. pSetValues < pnValuesEnd;
  617. ++ pSetValues, ++ pSetDef )
  618. {
  619. OutputF( stderr, "/D%s=%d ", pSetDef->Name(), *pSetValues );
  620. }
  621. OutputF( stderr, "%s\n", g_comboEmission.m_sSuffix.data() );
  622. // ------- end of OnCombo ---------------------
  623. }
  624. // Do a next iteration
  625. for ( pSetValues = pnValues, pSetDef = pDefVars;
  626. pSetValues < pnValuesEnd;
  627. ++ pSetValues, ++ pSetDef )
  628. {
  629. if ( -- *pSetValues >= pSetDef->Min() )
  630. goto next_combo_iteration;
  631. *pSetValues = pSetDef->Max();
  632. }
  633. }
  634. OutputF( stdout, "Generated %d combos: %d evaluated, %d skipped.\n", nTotalCombos, nSkipEvalCounters[1], nSkipEvalCounters[0] );
  635. }
  636. namespace ConfigurationProcessing
  637. {
  638. class CfgEntry
  639. {
  640. public:
  641. CfgEntry() : m_szName( "" ), m_szShaderSrc( "" ), m_pCg( NULL ), m_pExpr( NULL ) { memset( &m_eiInfo, 0, sizeof( m_eiInfo ) ); }
  642. static void Destroy( CfgEntry const &x ) { delete x.m_pCg; delete x.m_pExpr; }
  643. public:
  644. bool operator < ( CfgEntry const &x ) const { return m_pCg->NumCombos() < x.m_pCg->NumCombos(); }
  645. public:
  646. char const *m_szName;
  647. char const *m_szShaderSrc;
  648. ComboGenerator *m_pCg;
  649. CComplexExpression *m_pExpr;
  650. std::string m_sPrefix;
  651. std::string m_sSuffix;
  652. CfgProcessor::CfgEntryInfo m_eiInfo;
  653. };
  654. QuickStrUnique s_uniqueSections, s_strPool;
  655. std::multiset< CfgEntry > s_setEntries;
  656. class ComboHandleImpl : public IEvaluationContext
  657. {
  658. public:
  659. uint64 m_iTotalCommand;
  660. uint64 m_iComboNumber;
  661. uint64 m_numCombos;
  662. CfgEntry const *m_pEntry;
  663. public:
  664. ComboHandleImpl() : m_iTotalCommand( 0 ), m_iComboNumber( 0 ), m_numCombos( 0 ), m_pEntry( NULL ) {}
  665. // IEvaluationContext
  666. public:
  667. QuickArray < int > m_arrVarSlots;
  668. public:
  669. virtual int GetVariableValue( int nSlot ) { return m_arrVarSlots.Get( nSlot ); };
  670. virtual char const * GetVariableName( int nSlot ) { return m_pEntry->m_pCg->GetVariableName( nSlot ); };
  671. virtual int GetVariableSlot( char const *szVariableName ) { return m_pEntry->m_pCg->GetVariableSlot( szVariableName ); };
  672. // External implementation
  673. public:
  674. bool Initialize( uint64 iTotalCommand, const CfgEntry *pEntry );
  675. bool AdvanceCommands( uint64 &riAdvanceMore );
  676. bool NextNotSkipped( uint64 iTotalCommand );
  677. bool IsSkipped( void ) { return ( m_pEntry->m_pExpr->Evaluate( this ) != 0 ); }
  678. void FormatCommand( char *pchBuffer );
  679. };
  680. QuickMap < uint64, ComboHandleImpl > s_mapComboCommands;
  681. bool ComboHandleImpl::Initialize( uint64 iTotalCommand, const CfgEntry *pEntry )
  682. {
  683. m_iTotalCommand = iTotalCommand;
  684. m_pEntry = pEntry;
  685. m_numCombos = m_pEntry->m_pCg->NumCombos();
  686. // Defines
  687. Define const * const pDefVars = m_pEntry->m_pCg->GetDefinesBase();
  688. Define const * const pDefVarsEnd = m_pEntry->m_pCg->GetDefinesEnd();
  689. Define const *pSetDef;
  690. // Set all the variables to max values
  691. for ( pSetDef = pDefVars;
  692. pSetDef < pDefVarsEnd;
  693. ++ pSetDef )
  694. {
  695. m_arrVarSlots.Append( pSetDef->Max() );
  696. }
  697. m_iComboNumber = m_numCombos - 1;
  698. return true;
  699. }
  700. bool ComboHandleImpl::AdvanceCommands( uint64 &riAdvanceMore )
  701. {
  702. if ( !riAdvanceMore )
  703. return true;
  704. // Get the pointers
  705. int * const pnValues = m_arrVarSlots.ArrayBaseForEdit();
  706. int * const pnValuesEnd = pnValues + m_arrVarSlots.Size();
  707. int *pSetValues;
  708. // Defines
  709. Define const * const pDefVars = m_pEntry->m_pCg->GetDefinesBase();
  710. Define const *pSetDef;
  711. if ( m_iComboNumber < riAdvanceMore )
  712. {
  713. riAdvanceMore -= m_iComboNumber;
  714. return false;
  715. }
  716. // Do the advance
  717. m_iTotalCommand += riAdvanceMore;
  718. m_iComboNumber -= riAdvanceMore;
  719. for ( pSetValues = pnValues, pSetDef = pDefVars;
  720. ( pSetValues < pnValuesEnd ) && ( riAdvanceMore > 0 );
  721. ++ pSetValues, ++ pSetDef )
  722. {
  723. riAdvanceMore += ( pSetDef->Max() - *pSetValues );
  724. *pSetValues = pSetDef->Max();
  725. int iInterval = ( pSetDef->Max() - pSetDef->Min() + 1 );
  726. *pSetValues -= int( riAdvanceMore % iInterval );
  727. riAdvanceMore /= iInterval;
  728. }
  729. return true;
  730. }
  731. bool ComboHandleImpl::NextNotSkipped( uint64 iTotalCommand )
  732. {
  733. // Get the pointers
  734. int * const pnValues = m_arrVarSlots.ArrayBaseForEdit();
  735. int * const pnValuesEnd = pnValues + m_arrVarSlots.Size();
  736. int *pSetValues;
  737. // Defines
  738. Define const * const pDefVars = m_pEntry->m_pCg->GetDefinesBase();
  739. Define const *pSetDef;
  740. // Go ahead and run the iterations
  741. {
  742. next_combo_iteration:
  743. if ( m_iTotalCommand + 1 >= iTotalCommand ||
  744. !m_iComboNumber )
  745. return false;
  746. -- m_iComboNumber;
  747. ++ m_iTotalCommand;
  748. // Do a next iteration
  749. for ( pSetValues = pnValues, pSetDef = pDefVars;
  750. pSetValues < pnValuesEnd;
  751. ++ pSetValues, ++ pSetDef )
  752. {
  753. if ( -- *pSetValues >= pSetDef->Min() )
  754. goto have_combo_iteration;
  755. *pSetValues = pSetDef->Max();
  756. }
  757. return false;
  758. have_combo_iteration:
  759. if ( m_pEntry->m_pExpr->Evaluate( this ) )
  760. goto next_combo_iteration;
  761. else
  762. return true;
  763. }
  764. }
  765. void ComboHandleImpl::FormatCommand( char *pchBuffer )
  766. {
  767. // Get the pointers
  768. int * const pnValues = m_arrVarSlots.ArrayBaseForEdit();
  769. int * const pnValuesEnd = pnValues + m_arrVarSlots.Size();
  770. int *pSetValues;
  771. // Defines
  772. Define const * const pDefVars = m_pEntry->m_pCg->GetDefinesBase();
  773. Define const *pSetDef;
  774. {
  775. // ------- OnCombo( nCurrentCombo ); ----------
  776. sprintf( pchBuffer, "%s ", m_pEntry->m_sPrefix.data() );
  777. pchBuffer += strlen( pchBuffer );
  778. if ( g_bIsPS3 )
  779. {
  780. sprintf( pchBuffer, "-DSHADERCOMBO=%I64d ", m_iComboNumber );
  781. }
  782. else
  783. {
  784. sprintf( pchBuffer, "/DSHADERCOMBO=%I64d ", m_iComboNumber );
  785. }
  786. pchBuffer += strlen( pchBuffer );
  787. for ( pSetValues = pnValues, pSetDef = pDefVars;
  788. pSetValues < pnValuesEnd;
  789. ++ pSetValues, ++ pSetDef )
  790. {
  791. if ( g_bIsPS3 )
  792. {
  793. sprintf( pchBuffer, "-D%s=%d ", pSetDef->Name(), *pSetValues );
  794. }
  795. else
  796. {
  797. sprintf( pchBuffer, "/D%s=%d ", pSetDef->Name(), *pSetValues );
  798. }
  799. pchBuffer += strlen( pchBuffer );
  800. }
  801. sprintf( pchBuffer, "%s\n", m_pEntry->m_sSuffix.data() );
  802. pchBuffer += strlen( pchBuffer );
  803. // ------- end of OnCombo ---------------------
  804. }
  805. }
  806. struct CAutoDestroyEntries {
  807. ~CAutoDestroyEntries( void ) {
  808. std::for_each( s_setEntries.begin(), s_setEntries.end(), CfgEntry::Destroy );
  809. }
  810. } s_autoDestroyEntries;
  811. FILE *& GetInputStream( FILE * )
  812. {
  813. static FILE *s_fInput = stdin;
  814. return s_fInput;
  815. }
  816. CUtlInplaceBuffer *& GetInputStream( CUtlInplaceBuffer * )
  817. {
  818. static CUtlInplaceBuffer *s_fInput = NULL;
  819. return s_fInput;
  820. }
  821. char * GetLinePtr_Private( void )
  822. {
  823. if ( CUtlInplaceBuffer *pUtlBuffer = GetInputStream( ( CUtlInplaceBuffer * ) NULL ) )
  824. return pUtlBuffer->InplaceGetLinePtr();
  825. if ( FILE *fInput = GetInputStream( ( FILE * ) NULL ) )
  826. return fgets( g_chTmpBuffer, g_lenTmpBuffer, fInput );
  827. return NULL;
  828. }
  829. bool LineEquals( char const *sz1, char const *sz2, int nLen )
  830. {
  831. return 0 == strncmp( sz1, sz2, nLen );
  832. }
  833. char * NextLine( void )
  834. {
  835. if ( char *szLine = GetLinePtr_Private() )
  836. {
  837. // Trim trailing whitespace as well
  838. size_t len = ( size_t ) strlen( szLine );
  839. while ( len -- > 0 && V_isspace( szLine[ len ] ) )
  840. {
  841. szLine[ len ] = 0;
  842. }
  843. return szLine;
  844. }
  845. return NULL;
  846. }
  847. char * WaitFor( char const *szWaitString, int nMatchLength )
  848. {
  849. while ( char *pchResult = NextLine() )
  850. {
  851. if ( LineEquals( pchResult, szWaitString, nMatchLength ) )
  852. return pchResult;
  853. }
  854. return NULL;
  855. }
  856. bool ProcessSection( CfgEntry &cfge )
  857. {
  858. bool bStaticDefines;
  859. // Read the next line for the section src file
  860. if ( char *szLine = NextLine() )
  861. {
  862. cfge.m_szShaderSrc = s_strPool.AddLookup( szLine );
  863. }
  864. if ( char *szLine = WaitFor( "#DEFINES-", 9 ) )
  865. {
  866. bStaticDefines = ( szLine[9] == 'S' );
  867. }
  868. else
  869. return false;
  870. // Combo generator
  871. ComboGenerator &cg = *( cfge.m_pCg = new ComboGenerator );
  872. CComplexExpression &exprSkip = *( cfge.m_pExpr = new CComplexExpression( &cg ) );
  873. // #DEFINES:
  874. while ( char *szLine = NextLine() )
  875. {
  876. if ( LineEquals( szLine, "#SKIP", 5 ) )
  877. break;
  878. // static defines
  879. if ( LineEquals( szLine, "#DEFINES-", 9 ) )
  880. {
  881. bStaticDefines = ( szLine[9] == 'S' );
  882. continue;
  883. }
  884. while ( *szLine && V_isspace(*szLine) )
  885. {
  886. ++ szLine;
  887. }
  888. // Find the eq
  889. char *pchEq = strchr( szLine, '=' );
  890. if ( !pchEq )
  891. continue;
  892. char *pchStartRange = pchEq + 1;
  893. *pchEq = 0;
  894. while ( -- pchEq >= szLine &&
  895. V_isspace( *pchEq ) )
  896. {
  897. *pchEq = 0;
  898. }
  899. if ( !*szLine )
  900. continue;
  901. // Find the end of range
  902. char *pchEndRange = strstr( pchStartRange, ".." );
  903. if ( !pchEndRange )
  904. continue;
  905. pchEndRange += 2;
  906. // Create the define
  907. Define df( szLine, atoi( pchStartRange ), atoi( pchEndRange ), bStaticDefines );
  908. if ( df.Max() < df.Min() )
  909. continue;
  910. // Add the define
  911. cg.AddDefine( df );
  912. }
  913. // #SKIP:
  914. if ( char *szLine = NextLine() )
  915. {
  916. exprSkip.Parse( szLine );
  917. }
  918. else
  919. return false;
  920. // #COMMAND:
  921. if ( !WaitFor( "#COMMAND", 8 ) )
  922. return false;
  923. if ( char *szLine = NextLine() )
  924. cfge.m_sPrefix = szLine;
  925. if ( char *szLine = NextLine() )
  926. cfge.m_sSuffix = szLine;
  927. // #END
  928. if ( !WaitFor( "#END", 4 ) )
  929. return false;
  930. return true;
  931. }
  932. void UnrollSectionCommands( CfgEntry const &cfge )
  933. {
  934. // Execute the combo computation
  935. //
  936. //
  937. g_comboEmission.m_sPrefix = cfge.m_sPrefix;
  938. g_comboEmission.m_sSuffix = cfge.m_sSuffix;
  939. OutputF( stdout, "Preparing %d combos for %s...\n", cfge.m_pCg->NumCombos(), cfge.m_szName );
  940. OutputF( stderr, "#%s\n", cfge.m_szName );
  941. time_t tt_start = time( NULL );
  942. cfge.m_pCg->RunAllCombos( *cfge.m_pExpr );
  943. time_t tt_end = time( NULL );
  944. OutputF( stderr, "#%s\n", cfge.m_szName );
  945. OutputF( stdout, "Prepared %s combos. %d sec.\n", cfge.m_szName, ( int ) difftime( tt_end, tt_start ) );
  946. g_comboEmission.m_sPrefix = "";
  947. g_comboEmission.m_sSuffix = "";
  948. }
  949. void RunSection( CfgEntry const &cfge )
  950. {
  951. // Execute the combo computation
  952. //
  953. //
  954. g_comboEmission.m_sPrefix = cfge.m_sPrefix;
  955. g_comboEmission.m_sSuffix = cfge.m_sSuffix;
  956. OutputF( stdout, "Preparing %d combos for %s...\n", cfge.m_pCg->NumCombos(), cfge.m_szName );
  957. OutputF( stderr, "#%s\n", cfge.m_szName );
  958. time_t tt_start = time( NULL );
  959. cfge.m_pCg->RunAllCombos( *cfge.m_pExpr );
  960. time_t tt_end = time( NULL );
  961. OutputF( stderr, "#%s\n", cfge.m_szName );
  962. OutputF( stdout, "Prepared %s combos. %d sec.\n", cfge.m_szName, ( int ) difftime( tt_end, tt_start ) );
  963. g_comboEmission.m_sPrefix = "";
  964. g_comboEmission.m_sSuffix = "";
  965. }
  966. void ProcessConfiguration()
  967. {
  968. static bool s_bProcessOnce = false;
  969. while ( char *szLine = WaitFor( "#BEGIN", 6 ) )
  970. {
  971. if ( ' ' == szLine[6] && !s_uniqueSections.Add(szLine + 7) )
  972. continue;
  973. CfgEntry cfge;
  974. cfge.m_szName = s_uniqueSections.Lookup( szLine + 7 );
  975. ProcessSection( cfge );
  976. s_setEntries.insert( cfge );
  977. }
  978. uint64 nCurrentCommand = 0;
  979. for( std::multiset< CfgEntry >::reverse_iterator it = s_setEntries.rbegin(),
  980. itEnd = s_setEntries.rend(); it != itEnd; ++ it )
  981. {
  982. // We establish a command mapping for the beginning of the entry
  983. ComboHandleImpl chi;
  984. chi.Initialize( nCurrentCommand, &*it );
  985. s_mapComboCommands.Append( nCurrentCommand, chi );
  986. // We also establish mapping by either splitting the
  987. // combos into 500 intervals or stepping by every 1000 combos.
  988. int iPartStep = ( int ) MAX( 1000, ( chi.m_numCombos / 500 ) );
  989. for ( uint64 iRecord = nCurrentCommand + iPartStep;
  990. iRecord < nCurrentCommand + chi.m_numCombos;
  991. iRecord += iPartStep )
  992. {
  993. uint64 iAdvance = iPartStep;
  994. chi.AdvanceCommands( iAdvance );
  995. s_mapComboCommands.Append( iRecord, chi );
  996. }
  997. nCurrentCommand += chi.m_numCombos;
  998. }
  999. // Establish the last command terminator
  1000. {
  1001. static CfgEntry s_term;
  1002. s_term.m_eiInfo.m_iCommandStart = s_term.m_eiInfo.m_iCommandEnd = nCurrentCommand;
  1003. s_term.m_eiInfo.m_numCombos = s_term.m_eiInfo.m_numStaticCombos = s_term.m_eiInfo.m_numDynamicCombos = 1;
  1004. s_term.m_eiInfo.m_szName = s_term.m_eiInfo.m_szShaderFileName = "";
  1005. ComboHandleImpl chi;
  1006. chi.m_iTotalCommand = nCurrentCommand;
  1007. chi.m_pEntry = &s_term;
  1008. s_mapComboCommands.Append( nCurrentCommand, chi );
  1009. }
  1010. }
  1011. }; // namespace ConfigurationProcessing
  1012. /*
  1013. int main( int argc, char **argv )
  1014. {
  1015. if ( _isatty( _fileno( stdin ) ) )
  1016. {
  1017. return Usage();
  1018. }
  1019. // Go ahead processing the configuration
  1020. ConfigurationProcessing::ProcessConfiguration();
  1021. return 0;
  1022. }
  1023. */
  1024. namespace CfgProcessor
  1025. {
  1026. typedef ConfigurationProcessing::ComboHandleImpl CPCHI_t;
  1027. CPCHI_t * FromHandle( ComboHandle hCombo ) { return reinterpret_cast < CPCHI_t * > ( hCombo ); }
  1028. ComboHandle AsHandle( CPCHI_t *pImpl ) { return reinterpret_cast < ComboHandle > ( pImpl ); }
  1029. void ReadConfiguration( FILE *fInputStream )
  1030. {
  1031. CAutoPushPop < FILE * > pushInputStream( ConfigurationProcessing::GetInputStream( fInputStream ), fInputStream );
  1032. ConfigurationProcessing::ProcessConfiguration();
  1033. }
  1034. void ReadConfiguration( CUtlInplaceBuffer *fInputStream )
  1035. {
  1036. CAutoPushPop < CUtlInplaceBuffer * > pushInputStream( ConfigurationProcessing::GetInputStream( fInputStream ), fInputStream );
  1037. ConfigurationProcessing::ProcessConfiguration();
  1038. }
  1039. void DescribeConfiguration( CArrayAutoPtr < CfgEntryInfo > &rarrEntries )
  1040. {
  1041. rarrEntries.Delete();
  1042. rarrEntries.Attach( new CfgEntryInfo [ ConfigurationProcessing::s_setEntries.size() + 1 ] );
  1043. CfgEntryInfo *pInfo = rarrEntries.Get();
  1044. uint64 nCurrentCommand = 0;
  1045. for( std::multiset< ConfigurationProcessing::CfgEntry >::reverse_iterator it =
  1046. ConfigurationProcessing::s_setEntries.rbegin(),
  1047. itEnd = ConfigurationProcessing::s_setEntries.rend();
  1048. it != itEnd; ++ it, ++ pInfo )
  1049. {
  1050. ConfigurationProcessing::CfgEntry const &e = *it;
  1051. pInfo->m_szName = e.m_szName;
  1052. pInfo->m_szShaderFileName = e.m_szShaderSrc;
  1053. pInfo->m_iCommandStart = nCurrentCommand;
  1054. pInfo->m_numCombos = e.m_pCg->NumCombos();
  1055. pInfo->m_numDynamicCombos = e.m_pCg->NumCombos( false );
  1056. pInfo->m_numStaticCombos = e.m_pCg->NumCombos( true );
  1057. pInfo->m_iCommandEnd = pInfo->m_iCommandStart + pInfo->m_numCombos;
  1058. const_cast< CfgEntryInfo & > ( e.m_eiInfo ) = *pInfo;
  1059. nCurrentCommand += pInfo->m_numCombos;
  1060. }
  1061. // Terminator
  1062. memset( pInfo, 0, sizeof( CfgEntryInfo ) );
  1063. pInfo->m_iCommandStart = nCurrentCommand;
  1064. pInfo->m_iCommandEnd = nCurrentCommand;
  1065. }
  1066. ComboHandle Combo_GetCombo( uint64 iCommandNumber )
  1067. {
  1068. // Find earlier command
  1069. uint64 iCommandFound = iCommandNumber;
  1070. CPCHI_t emptyCPCHI;
  1071. CPCHI_t const &chiFound = ConfigurationProcessing::s_mapComboCommands.GetLessOrEq( iCommandFound, emptyCPCHI );
  1072. if ( chiFound.m_iTotalCommand < 0 ||
  1073. chiFound.m_iTotalCommand > iCommandNumber )
  1074. return NULL;
  1075. // Advance the handle as needed
  1076. CPCHI_t *pImpl = new CPCHI_t( chiFound );
  1077. uint64 iCommandFoundAdvance = iCommandNumber - iCommandFound;
  1078. pImpl->AdvanceCommands( iCommandFoundAdvance );
  1079. return AsHandle( pImpl );
  1080. }
  1081. ComboHandle Combo_GetNext( uint64 &riCommandNumber, ComboHandle &rhCombo, uint64 iCommandEnd )
  1082. {
  1083. // Combo handle implementation
  1084. CPCHI_t *pImpl = FromHandle( rhCombo );
  1085. if ( !rhCombo )
  1086. {
  1087. // We don't have a combo handle that corresponds to the command
  1088. // Find earlier command
  1089. uint64 iCommandFound = riCommandNumber;
  1090. CPCHI_t emptyCPCHI;
  1091. CPCHI_t const &chiFound = ConfigurationProcessing::s_mapComboCommands.GetLessOrEq( iCommandFound, emptyCPCHI );
  1092. if ( !chiFound.m_pEntry ||
  1093. !chiFound.m_pEntry->m_pCg ||
  1094. !chiFound.m_pEntry->m_pExpr ||
  1095. chiFound.m_iTotalCommand < 0 ||
  1096. chiFound.m_iTotalCommand > riCommandNumber )
  1097. return NULL;
  1098. // Advance the handle as needed
  1099. pImpl = new CPCHI_t( chiFound );
  1100. rhCombo = AsHandle( pImpl );
  1101. uint64 iCommandFoundAdvance = riCommandNumber - iCommandFound;
  1102. pImpl->AdvanceCommands( iCommandFoundAdvance );
  1103. if ( !pImpl->IsSkipped() )
  1104. return rhCombo;
  1105. }
  1106. for ( ; ; )
  1107. {
  1108. // We have the combo handle now
  1109. if ( pImpl->NextNotSkipped( iCommandEnd ) )
  1110. {
  1111. riCommandNumber = pImpl->m_iTotalCommand;
  1112. return rhCombo;
  1113. }
  1114. // We failed to get the next combo command (out of range)
  1115. if ( pImpl->m_iTotalCommand + 1 >= iCommandEnd )
  1116. {
  1117. delete pImpl;
  1118. rhCombo = NULL;
  1119. riCommandNumber = iCommandEnd;
  1120. return NULL;
  1121. }
  1122. // Otherwise we just have to obtain the next combo handle
  1123. riCommandNumber = pImpl->m_iTotalCommand + 1;
  1124. // Delete the old combo handle
  1125. delete pImpl;
  1126. rhCombo = NULL;
  1127. // Retrieve the next combo handle data
  1128. uint64 iCommandLookup = riCommandNumber;
  1129. CPCHI_t emptyCPCHI;
  1130. CPCHI_t const &chiNext = ConfigurationProcessing::s_mapComboCommands.GetLessOrEq( iCommandLookup, emptyCPCHI );
  1131. Assert( ( iCommandLookup == riCommandNumber ) && ( chiNext.m_pEntry ) );
  1132. // Set up the new combo handle
  1133. pImpl = new CPCHI_t( chiNext );
  1134. rhCombo = AsHandle( pImpl );
  1135. if ( !pImpl->IsSkipped() )
  1136. return rhCombo;
  1137. }
  1138. }
  1139. void Combo_FormatCommand( ComboHandle hCombo, char *pchBuffer )
  1140. {
  1141. CPCHI_t *pImpl = FromHandle( hCombo );
  1142. pImpl->FormatCommand( pchBuffer );
  1143. }
  1144. uint64 Combo_GetCommandNum( ComboHandle hCombo )
  1145. {
  1146. if ( CPCHI_t *pImpl = FromHandle( hCombo ) )
  1147. return pImpl->m_iTotalCommand;
  1148. else
  1149. return ~uint64(0);
  1150. }
  1151. uint64 Combo_GetComboNum( ComboHandle hCombo )
  1152. {
  1153. if ( CPCHI_t *pImpl = FromHandle( hCombo ) )
  1154. return pImpl->m_iComboNumber;
  1155. else
  1156. return ~uint64(0);
  1157. }
  1158. CfgEntryInfo const *Combo_GetEntryInfo( ComboHandle hCombo )
  1159. {
  1160. if ( CPCHI_t *pImpl = FromHandle( hCombo ) )
  1161. return &pImpl->m_pEntry->m_eiInfo;
  1162. else
  1163. return NULL;
  1164. }
  1165. ComboHandle Combo_Alloc( ComboHandle hComboCopyFrom )
  1166. {
  1167. if ( hComboCopyFrom )
  1168. return AsHandle( new CPCHI_t( * FromHandle( hComboCopyFrom ) ) );
  1169. else
  1170. return AsHandle( new CPCHI_t );
  1171. }
  1172. void Combo_Assign( ComboHandle hComboDst, ComboHandle hComboSrc )
  1173. {
  1174. Assert( hComboDst );
  1175. * FromHandle( hComboDst ) = * FromHandle( hComboSrc );
  1176. }
  1177. void Combo_Free( ComboHandle &rhComboFree )
  1178. {
  1179. delete FromHandle( rhComboFree );
  1180. rhComboFree = NULL;
  1181. }
  1182. }; // namespace CfgProcessor