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.

744 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #define PROTECTED_THINGS_DISABLE
  7. #undef PROTECT_FILEIO_FUNCTIONS
  8. #undef fopen
  9. #include <windows.h>
  10. #include "basetypes.h"
  11. #include "utlvector.h"
  12. #include "utlsymbol.h"
  13. #include "utldict.h"
  14. #include "utlbuffer.h"
  15. #include "bugreporter/bugreporter.h"
  16. #include "filesystem_tools.h"
  17. #include "KeyValues.h"
  18. IFileSystem *g_filesystem = NULL;
  19. class CBug
  20. {
  21. public:
  22. CBug()
  23. {
  24. Clear();
  25. }
  26. void Clear()
  27. {
  28. Q_memset( title, 0, sizeof( title ) );
  29. Q_memset( desc, 0, sizeof( desc ) );
  30. Q_memset( submitter, 0, sizeof( submitter ) );
  31. Q_memset( owner, 0, sizeof( owner ) );
  32. Q_memset( severity, 0, sizeof( severity ) );
  33. Q_memset( priority, 0, sizeof( priority ) );
  34. Q_memset( area, 0, sizeof( area ) );
  35. Q_memset( mapnumber, 0, sizeof( mapnumber) );
  36. Q_memset( reporttype, 0, sizeof( reporttype ) );
  37. Q_memset( level, 0, sizeof( level ) );
  38. Q_memset( build, 0, sizeof( build ) );
  39. Q_memset( position, 0, sizeof( position ) );
  40. Q_memset( orientation, 0, sizeof( orientation ) );
  41. Q_memset( screenshot_unc, 0, sizeof( screenshot_unc ) );
  42. Q_memset( savegame_unc, 0, sizeof( savegame_unc ) );
  43. Q_memset( bsp_unc, 0, sizeof( bsp_unc ) );
  44. Q_memset( vmf_unc, 0, sizeof( vmf_unc ) );
  45. Q_memset( driverinfo, 0, sizeof( driverinfo ) );
  46. Q_memset( misc, 0, sizeof( misc ) );
  47. includedfiles.Purge();
  48. }
  49. char title[ 256 ];
  50. char desc[ 8192 ];
  51. char owner[ 256 ];
  52. char submitter[ 256 ];
  53. char severity[ 256 ];
  54. char priority[ 256 ];
  55. char area[ 256 ];
  56. char mapnumber[ 256 ];
  57. char reporttype[ 256 ];
  58. char level[ 256 ];
  59. char build[ 256 ];
  60. char position[ 256 ];
  61. char orientation[ 256 ];
  62. char screenshot_unc[ 256 ];
  63. char savegame_unc[ 256 ];
  64. char bsp_unc[ 256 ];
  65. char vmf_unc[ 256 ];
  66. char driverinfo[ 2048 ];
  67. char misc[ 1024 ];
  68. struct incfile
  69. {
  70. char name[ 256 ];
  71. };
  72. CUtlVector< incfile > includedfiles;
  73. };
  74. class CBugReporter : public IBugReporter
  75. {
  76. public:
  77. CBugReporter();
  78. virtual ~CBugReporter();
  79. // Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  80. virtual bool Init( CreateInterfaceFn engineFactory );
  81. virtual void Shutdown();
  82. virtual bool IsPublicUI() { return false; }
  83. virtual char const *GetUserName();
  84. virtual char const *GetUserName_Display();
  85. virtual int GetNameCount();
  86. virtual char const *GetName( int index );
  87. virtual int GetDisplayNameCount();
  88. virtual char const *GetDisplayName( int index );
  89. virtual char const *GetDisplayNameForUserName( char const *username );
  90. virtual char const *GetUserNameForDisplayName( char const *display );
  91. virtual int GetSeverityCount();
  92. virtual char const *GetSeverity( int index );
  93. virtual int GetPriorityCount();
  94. virtual char const *GetPriority( int index );
  95. virtual int GetAreaCount();
  96. virtual char const *GetArea( int index );
  97. virtual int GetAreaMapCount();
  98. virtual char const *GetAreaMap( int index );
  99. virtual int GetMapNumberCount();
  100. virtual char const *GetMapNumber( int index );
  101. virtual int GetReportTypeCount();
  102. virtual char const *GetReportType( int index );
  103. virtual char const *GetRepositoryURL( void );
  104. virtual char const *GetSubmissionURL( void );
  105. virtual int GetLevelCount(int area) { return 0; }
  106. virtual char const *GetLevel(int area, int index ) { return ""; }
  107. // Submission API
  108. virtual void StartNewBugReport();
  109. virtual void CancelNewBugReport();
  110. virtual bool CommitBugReport( int& bugSubmissionId );
  111. virtual void SetTitle( char const *title );
  112. virtual void SetDescription( char const *description );
  113. // NULL for current user
  114. virtual void SetSubmitter( char const *username = 0 );
  115. virtual void SetOwner( char const *username );
  116. virtual void SetSeverity( char const *severity );
  117. virtual void SetPriority( char const *priority );
  118. virtual void SetArea( char const *area );
  119. virtual void SetMapNumber ( char const *mapnumber );
  120. virtual void SetReportType( char const *reporttype );
  121. virtual void SetLevel( char const *levelnamne );
  122. virtual void SetPosition( char const *position );
  123. virtual void SetOrientation( char const *pitch_yaw_roll );
  124. virtual void SetBuildNumber( char const *build_num );
  125. virtual void SetScreenShot( char const *screenshot_unc_address );
  126. virtual void SetSaveGame( char const *savegame_unc_address );
  127. virtual void SetBSPName( char const *bsp_unc_address );
  128. virtual void SetVMFName( char const *vmf_unc_address );
  129. virtual void AddIncludedFile( char const *filename );
  130. virtual void ResetIncludedFiles();
  131. virtual void SetZipAttachmentName( char const *zipfilename ) {} // only used by public bug reporter
  132. virtual void SetDriverInfo( char const *info );
  133. virtual void SetMiscInfo( char const *info );
  134. // These are stubbed here, but are used by the public version...
  135. virtual void SetCSERAddress( const struct netadr_s& adr ) {}
  136. virtual void SetExeName( char const *exename ) {}
  137. virtual void SetGameDirectory( char const *pchGamedir ) {}
  138. virtual void SetRAM( int ram ) {}
  139. virtual void SetCPU( int cpu ) {}
  140. virtual void SetProcessor( char const *processor ) {}
  141. virtual void SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device ) {}
  142. virtual void SetOSVersion( char const *osversion ) {}
  143. virtual void SetSteamUserID( void *steamid, int idsize ) {};
  144. private:
  145. bool PopulateLists();
  146. bool PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list );
  147. void SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src );
  148. CUtlSymbolTable m_BugStrings;
  149. CUtlVector< CUtlSymbol > m_Severity;
  150. CUtlVector< CUtlSymbol > m_SortedDisplayNames;
  151. CUtlVector< CUtlSymbol > m_Priority;
  152. CUtlVector< CUtlSymbol > m_Area;
  153. CUtlVector< CUtlSymbol > m_AreaMap;
  154. CUtlVector< CUtlSymbol > m_MapNumber;
  155. CUtlVector< CUtlSymbol > m_ReportType;
  156. CUtlSymbol m_UserName;
  157. CBug *m_pBug;
  158. char m_BugRootDirectory[512];
  159. KeyValues *m_OptionsFile;
  160. int m_CurrentBugID;
  161. char m_CurrentBugDirectory[512];
  162. };
  163. CBugReporter::CBugReporter()
  164. {
  165. m_pBug = NULL;
  166. m_CurrentBugID = 0;
  167. }
  168. CBugReporter::~CBugReporter()
  169. {
  170. m_BugStrings.RemoveAll();
  171. m_Severity.Purge();
  172. m_SortedDisplayNames.Purge();
  173. m_Priority.Purge();
  174. m_Area.Purge();
  175. m_MapNumber.Purge();
  176. m_ReportType.Purge();
  177. delete m_pBug;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  181. // Output : Returns true on success, false on failure.
  182. //-----------------------------------------------------------------------------
  183. bool CBugReporter::Init( CreateInterfaceFn engineFactory )
  184. {
  185. if ( engineFactory )
  186. {
  187. g_filesystem = (IFileSystem *)engineFactory( FILESYSTEM_INTERFACE_VERSION, NULL );
  188. if ( !g_filesystem )
  189. {
  190. AssertMsg( 0, "Failed to create/get IFileSystem" );
  191. return false;
  192. }
  193. }
  194. // Load our bugreporter_text options file
  195. m_OptionsFile = new KeyValues( "OptionsFile" );
  196. if ( !m_OptionsFile->LoadFromFile( g_filesystem, "bugreporter_text.txt", "EXECUTABLE_PATH" ) )
  197. {
  198. AssertMsg( 0, "Failed to load bugreporter_text options file." );
  199. return false;
  200. }
  201. strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory", "." ), sizeof(m_BugRootDirectory) );
  202. PopulateLists();
  203. return true;
  204. }
  205. void CBugReporter::Shutdown()
  206. {
  207. }
  208. char const *CBugReporter::GetUserName()
  209. {
  210. return m_BugStrings.String( m_UserName );
  211. }
  212. char const *CBugReporter::GetUserName_Display()
  213. {
  214. return GetDisplayNameForUserName( GetUserName() );
  215. }
  216. int CBugReporter::GetNameCount()
  217. {
  218. return GetDisplayNameCount();
  219. }
  220. char const *CBugReporter::GetName( int index )
  221. {
  222. return GetDisplayName(index);
  223. }
  224. int CBugReporter::GetDisplayNameCount()
  225. {
  226. return m_SortedDisplayNames.Count();
  227. }
  228. char const *CBugReporter::GetDisplayName( int index )
  229. {
  230. if ( index < 0 || index >= (int)m_SortedDisplayNames.Count() )
  231. return "<<Invalid>>";
  232. return m_BugStrings.String( m_SortedDisplayNames[ index ] );
  233. }
  234. char const *CBugReporter::GetDisplayNameForUserName( char const *username )
  235. {
  236. return username;
  237. }
  238. char const *CBugReporter::GetUserNameForDisplayName( char const *display )
  239. {
  240. return display;
  241. }
  242. int CBugReporter::GetSeverityCount()
  243. {
  244. return m_Severity.Count() ;
  245. }
  246. char const *CBugReporter::GetSeverity( int index )
  247. {
  248. if ( index < 0 || index >= m_Severity.Count() )
  249. return "<<Invalid>>";
  250. return m_BugStrings.String( m_Severity[ index ] );
  251. }
  252. int CBugReporter::GetPriorityCount()
  253. {
  254. return m_Priority.Count();
  255. }
  256. char const *CBugReporter::GetPriority( int index )
  257. {
  258. if ( index < 0 || index >= m_Priority.Count() )
  259. return "<<Invalid>>";
  260. return m_BugStrings.String( m_Priority[ index ] );
  261. }
  262. int CBugReporter::GetAreaCount()
  263. {
  264. return m_Area.Count();
  265. }
  266. char const *CBugReporter::GetArea( int index )
  267. {
  268. if ( index < 0 || index >= m_Area.Count() )
  269. return "<<Invalid>>";
  270. return m_BugStrings.String( m_Area[ index ] );
  271. }
  272. int CBugReporter::GetAreaMapCount()
  273. {
  274. return m_AreaMap.Count();
  275. }
  276. char const *CBugReporter::GetAreaMap( int index )
  277. {
  278. if ( index < 0 || index >= m_AreaMap.Count() )
  279. return "<<Invalid>>";
  280. return m_BugStrings.String( m_AreaMap[ index ] );
  281. }
  282. int CBugReporter::GetMapNumberCount()
  283. {
  284. return m_MapNumber.Count();
  285. }
  286. char const *CBugReporter::GetMapNumber( int index )
  287. {
  288. if ( index < 0 || index >= m_MapNumber.Count() )
  289. return "<<Invalid>>";
  290. return m_BugStrings.String( m_MapNumber[ index ] );
  291. }
  292. int CBugReporter::GetReportTypeCount()
  293. {
  294. return m_ReportType.Count();
  295. }
  296. char const *CBugReporter::GetReportType( int index )
  297. {
  298. if ( index < 0 || index >= m_ReportType.Count() )
  299. return "<<Invalid>>";
  300. return m_BugStrings.String( m_ReportType[ index ] );
  301. }
  302. char const *CBugReporter::GetRepositoryURL( void )
  303. {
  304. return m_BugRootDirectory;
  305. }
  306. char const *CBugReporter::GetSubmissionURL( void )
  307. {
  308. return m_CurrentBugDirectory;
  309. }
  310. void CBugReporter::StartNewBugReport()
  311. {
  312. if ( !m_pBug )
  313. {
  314. m_pBug = new CBug();
  315. }
  316. else
  317. {
  318. m_pBug->Clear();
  319. }
  320. // Find the first available bug number by looking
  321. // for the next directory that doesn't exist.
  322. m_CurrentBugID = 0;
  323. do
  324. {
  325. m_CurrentBugID++;
  326. Q_snprintf(m_CurrentBugDirectory, sizeof(m_CurrentBugDirectory), "%s/%d", m_BugRootDirectory, m_CurrentBugID );
  327. } while ( g_filesystem->FileExists( m_CurrentBugDirectory ) );
  328. g_filesystem->CreateDirHierarchy( m_CurrentBugDirectory );
  329. }
  330. void CBugReporter::CancelNewBugReport()
  331. {
  332. if ( !m_pBug )
  333. return;
  334. m_pBug->Clear();
  335. m_CurrentBugID = 0;
  336. }
  337. void CBugReporter::SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src )
  338. {
  339. out[ 0 ] = 0;
  340. char *dest = out;
  341. src.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  342. char const *replace = "\\BugId\\";
  343. int replace_len = Q_strlen( replace );
  344. for ( int pos = 0; pos <= src.TellPut() && ( ( dest - out ) < outlen ); )
  345. {
  346. char const *str = ( char const * )src.PeekGet( pos );
  347. if ( !Q_strnicmp( str, replace, replace_len ) )
  348. {
  349. *dest++ = '\\';
  350. char num[ 32 ];
  351. Q_snprintf( num, sizeof( num ), "%i", bugid );
  352. char *pnum = num;
  353. while ( *pnum )
  354. {
  355. *dest++ = *pnum++;
  356. }
  357. *dest++ = '\\';
  358. pos += replace_len;
  359. continue;
  360. }
  361. *dest++ = *str;
  362. ++pos;
  363. }
  364. *dest = 0;
  365. }
  366. bool CBugReporter::CommitBugReport( int& bugSubmissionId )
  367. {
  368. bugSubmissionId = m_CurrentBugID;
  369. if ( !m_pBug )
  370. return false;
  371. // Now create the bug descriptor file, and dump all the text keys in it
  372. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  373. buf.Printf( "%s\n\n", m_pBug->title );
  374. buf.Printf( "Owner: %s\n", m_pBug->owner );
  375. buf.Printf( "Submitter: %s\n", m_pBug->submitter );
  376. buf.Printf( "Severity: %s\n", m_pBug->severity );
  377. buf.Printf( "Type: %s\n", m_pBug->reporttype );
  378. buf.Printf( "Priority: %s\n", m_pBug->priority );
  379. buf.Printf( "Area: %s\n", m_pBug->area );
  380. //buf.Printf( "Map Number: %s\n", m_pBug->mapnumber ); // Ignoring, since the bsp name is in the title
  381. buf.Printf( "\n%s\n\n", m_pBug->desc );
  382. buf.Printf( "level: %s\nbuild: %s\nposition: setpos %s; setang %s\n",
  383. m_pBug->level,
  384. m_pBug->build,
  385. m_pBug->position,
  386. m_pBug->orientation );
  387. if ( m_pBug->screenshot_unc[ 0 ] )
  388. {
  389. buf.Printf( "screenshot: %s\n", m_pBug->screenshot_unc );
  390. }
  391. if ( m_pBug->savegame_unc[ 0 ] )
  392. {
  393. buf.Printf( "savegame: %s\n", m_pBug->savegame_unc );
  394. }
  395. if ( m_pBug->bsp_unc[ 0 ] )
  396. {
  397. buf.Printf( "bsp: %s\n", m_pBug->bsp_unc );
  398. }
  399. if ( m_pBug->vmf_unc[ 0 ] )
  400. {
  401. buf.Printf( "vmf: %s\n", m_pBug->vmf_unc );
  402. }
  403. if ( m_pBug->includedfiles.Count() > 0 )
  404. {
  405. int c = m_pBug->includedfiles.Count();
  406. for ( int i = 0 ; i < c; ++i )
  407. {
  408. buf.Printf( "include: %s\n", m_pBug->includedfiles[ i ].name );
  409. }
  410. }
  411. if ( m_pBug->driverinfo[ 0 ] )
  412. {
  413. buf.Printf( "%s\n", m_pBug->driverinfo );
  414. }
  415. if ( m_pBug->misc[ 0 ] )
  416. {
  417. buf.Printf( "%s\n", m_pBug->misc );
  418. }
  419. buf.PutChar( 0 );
  420. // Replace the "BugId" strings in the buffer with the bug ID
  421. int textbuflen = 2 * buf.TellPut() + 1;
  422. char *textbuf = new char [ textbuflen ];
  423. Q_memset( textbuf, 0, textbuflen );
  424. SubstituteBugId( bugSubmissionId, textbuf, textbuflen, buf );
  425. buf.Clear();
  426. buf.PutString( textbuf );
  427. // Write it out to the file
  428. char szBugFileName[1024];
  429. Q_snprintf(szBugFileName, sizeof(szBugFileName), "%s/bug.txt", m_CurrentBugDirectory );
  430. g_filesystem->WriteFile( szBugFileName, NULL, buf );
  431. // Clear the bug
  432. m_pBug->Clear();
  433. return true;
  434. }
  435. void CBugReporter::SetTitle( char const *title )
  436. {
  437. Assert( m_pBug );
  438. Q_strncpy( m_pBug->title, title, sizeof( m_pBug->title ) );
  439. }
  440. void CBugReporter::SetDescription( char const *description )
  441. {
  442. Assert( m_pBug );
  443. Q_strncpy( m_pBug->desc, description, sizeof( m_pBug->desc ) );
  444. }
  445. void CBugReporter::SetSubmitter( char const *username /*= 0*/ )
  446. {
  447. if ( !username )
  448. {
  449. username = GetUserName();
  450. }
  451. Assert( m_pBug );
  452. Q_strncpy( m_pBug->submitter, username, sizeof( m_pBug->submitter ) );
  453. }
  454. void CBugReporter::SetOwner( char const *username )
  455. {
  456. Assert( m_pBug );
  457. Q_strncpy( m_pBug->owner, username, sizeof( m_pBug->owner ) );
  458. }
  459. void CBugReporter::SetSeverity( char const *severity )
  460. {
  461. Assert( m_pBug );
  462. Q_strncpy( m_pBug->severity, severity, sizeof( m_pBug->severity ) );
  463. }
  464. void CBugReporter::SetPriority( char const *priority )
  465. {
  466. Assert( m_pBug );
  467. Q_strncpy( m_pBug->priority, priority, sizeof( m_pBug->priority ) );
  468. }
  469. void CBugReporter::SetArea( char const *area )
  470. {
  471. Assert( m_pBug );
  472. Q_strncpy( m_pBug->area, area, sizeof( m_pBug->area ) );
  473. }
  474. void CBugReporter::SetMapNumber( char const *mapnumber )
  475. {
  476. Assert( m_pBug);
  477. Q_strncpy( m_pBug->mapnumber, mapnumber, sizeof( m_pBug->mapnumber ) );
  478. }
  479. void CBugReporter::SetReportType( char const *reporttype )
  480. {
  481. Assert( m_pBug );
  482. Q_strncpy( m_pBug->reporttype, reporttype, sizeof( m_pBug->reporttype ) );
  483. }
  484. void CBugReporter::SetLevel( char const *levelnamne )
  485. {
  486. Assert( m_pBug );
  487. Q_strncpy( m_pBug->level, levelnamne, sizeof( m_pBug->level ) );
  488. }
  489. void CBugReporter::SetDriverInfo( char const *info )
  490. {
  491. Assert( m_pBug );
  492. Q_strncpy( m_pBug->driverinfo, info, sizeof( m_pBug->driverinfo ) );
  493. }
  494. void CBugReporter::SetMiscInfo( char const *info )
  495. {
  496. Assert( m_pBug );
  497. Q_strncpy( m_pBug->misc, info, sizeof( m_pBug->misc ) );
  498. }
  499. void CBugReporter::SetPosition( char const *position )
  500. {
  501. Assert( m_pBug );
  502. Q_strncpy( m_pBug->position, position, sizeof( m_pBug->position ) );
  503. }
  504. void CBugReporter::SetOrientation( char const *pitch_yaw_roll )
  505. {
  506. Assert( m_pBug );
  507. Q_strncpy( m_pBug->orientation, pitch_yaw_roll, sizeof( m_pBug->orientation ) );
  508. }
  509. void CBugReporter::SetBuildNumber( char const *build_num )
  510. {
  511. Assert( m_pBug );
  512. Q_strncpy( m_pBug->build, build_num, sizeof( m_pBug->build ) );
  513. }
  514. void CBugReporter::SetScreenShot( char const *screenshot_unc_address )
  515. {
  516. Assert( m_pBug );
  517. Q_strncpy( m_pBug->screenshot_unc, screenshot_unc_address, sizeof( m_pBug->screenshot_unc ) );
  518. }
  519. void CBugReporter::SetSaveGame( char const *savegame_unc_address )
  520. {
  521. Assert( m_pBug );
  522. Q_strncpy( m_pBug->savegame_unc, savegame_unc_address, sizeof( m_pBug->savegame_unc ) );
  523. }
  524. void CBugReporter::SetBSPName( char const *bsp_unc_address )
  525. {
  526. Assert( m_pBug );
  527. Q_strncpy( m_pBug->bsp_unc, bsp_unc_address, sizeof( m_pBug->bsp_unc ) );
  528. }
  529. void CBugReporter::SetVMFName( char const *vmf_unc_address )
  530. {
  531. Assert( m_pBug );
  532. Q_strncpy( m_pBug->vmf_unc, vmf_unc_address, sizeof( m_pBug->vmf_unc ) );
  533. }
  534. void CBugReporter::AddIncludedFile( char const *filename )
  535. {
  536. CBug::incfile includedfile;
  537. Q_strncpy( includedfile.name, filename, sizeof( includedfile.name ) );
  538. m_pBug->includedfiles.AddToTail( includedfile );
  539. }
  540. void CBugReporter::ResetIncludedFiles()
  541. {
  542. m_pBug->includedfiles.Purge();
  543. }
  544. bool CBugReporter::PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list )
  545. {
  546. // Read choice lists from text file
  547. KeyValues *pKV = m_OptionsFile->FindKey( listname );
  548. pKV = pKV->GetFirstSubKey();
  549. while ( pKV )
  550. {
  551. CUtlSymbol sym = m_BugStrings.AddString( pKV->GetName() );
  552. list.AddToTail( sym );
  553. pKV = pKV->GetNextKey();
  554. }
  555. return true;
  556. }
  557. // owner, not required <<Unassigned>>
  558. // area <<None>>
  559. bool CBugReporter::PopulateLists()
  560. {
  561. CUtlSymbol unassigned = m_BugStrings.AddString( "<<Unassigned>>" );
  562. CUtlSymbol none = m_BugStrings.AddString( "<<None>>" );
  563. m_Area.AddToTail( none );
  564. m_MapNumber.AddToTail( none );
  565. m_SortedDisplayNames.AddToTail( unassigned );
  566. PopulateChoiceList( "Severity", m_Severity );
  567. PopulateChoiceList( "Report Type", m_ReportType );
  568. PopulateChoiceList( "Area", m_Area );
  569. PopulateChoiceList( "Area@Dir%Map", m_AreaMap );
  570. PopulateChoiceList( "Map Number", m_MapNumber );
  571. PopulateChoiceList( "Priority", m_Priority );
  572. // Get developer names from text file
  573. KeyValues *pKV = m_OptionsFile->FindKey( "Names" );
  574. pKV = pKV->GetFirstSubKey();
  575. while ( pKV )
  576. {
  577. // Fill in lookup table
  578. CUtlSymbol display_name_sym = m_BugStrings.AddString( pKV->GetName() );
  579. m_SortedDisplayNames.AddToTail( display_name_sym );
  580. pKV = pKV->GetNextKey();
  581. }
  582. /*
  583. // Now sort display names
  584. int c = m_SortedDisplayNames.Count();
  585. for ( int i = 1 ; i < c; i++ )
  586. {
  587. for ( int j = i + 1; j < c; j++ )
  588. {
  589. char const *p1 = m_BugStrings.String( m_SortedDisplayNames[ i ] );
  590. char const *p2 = m_BugStrings.String( m_SortedDisplayNames[ j ] );
  591. int cmp = Q_stricmp( p1, p2 );
  592. if ( cmp > 0 )
  593. {
  594. CUtlSymbol t = m_SortedDisplayNames[ i ];
  595. m_SortedDisplayNames[ i ] = m_SortedDisplayNames[ j ];
  596. m_SortedDisplayNames[ j ] = t;
  597. }
  598. }
  599. }
  600. */
  601. return true;
  602. }
  603. EXPOSE_SINGLE_INTERFACE( CBugReporter, IBugReporter, INTERFACEVERSION_BUGREPORTER );