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.

1399 lines
36 KiB

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