summaryrefslogtreecommitdiff
path: root/utils/dxsupportclean
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/dxsupportclean
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/dxsupportclean')
-rw-r--r--utils/dxsupportclean/dxsupportclean.cpp356
-rw-r--r--utils/dxsupportclean/dxsupportclean.vpc37
2 files changed, 393 insertions, 0 deletions
diff --git a/utils/dxsupportclean/dxsupportclean.cpp b/utils/dxsupportclean/dxsupportclean.cpp
new file mode 100644
index 0000000..e8f946f
--- /dev/null
+++ b/utils/dxsupportclean/dxsupportclean.cpp
@@ -0,0 +1,356 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Clean dxsupport.csv by sorting and merging existing records
+// Can also parse survey php and merge new data into dxsupport.csv
+//
+//===============================================================================
+
+#include "tier0/platform.h"
+#include "tier0/progressbar.h"
+#include "tier2/tier2.h"
+#include "tier0/memdbgon.h"
+#include "filesystem.h"
+#include "icommandline.h"
+#include "tier1/utlstringmap.h"
+#include "tier1/strtools.h"
+#include "tier1/utlmap.h"
+#include "tier2/fileutils.h"
+#include "stdlib.h"
+
+#include "tier0/dbg.h"
+
+
+#define MAX_RECORDS 128
+
+struct DeviceRecord_t {
+ char szName[256];
+ char szData[MAX_RECORDS][64]; // No more than MAX_RECORDS columns of data in dxsupport.cfg
+};
+
+int g_nVendorIDIndex;
+int g_nDeviceMinIDIndex;
+int g_nDeviceMaxIDIndex;
+int g_nNumDXSupportColumns = 0;
+bool g_bMergeConflict = false;
+
+static void GrabSurveyData( char const *pInputFilename, char const *pOutputFilename )
+{
+ CRequiredInputTextFile f( pInputFilename );
+ COutputTextFile o( pOutputFilename );
+ char linebuffer[4096], szDummy[32], szVendorID[32], szDeviceID[32], szPartName[256], goodLine[] = "$vend_dev_to_name[ MakeLookup(";
+
+ while ( f.ReadLine( linebuffer, sizeof( linebuffer ) ) )
+ {
+ if ( !strncmp( linebuffer, goodLine, strlen( goodLine ) ) ) // specific pattern on the line we want
+ {
+ V_strncpy( szDummy, strtok( linebuffer, ",()\"" ), sizeof( szDummy ) );
+ V_strncpy( szVendorID, strtok( NULL, ",()\"" ), sizeof( szVendorID ) );
+ V_strncpy( szDeviceID, strtok( NULL, ",()\"" ), sizeof( szDeviceID ) );
+ V_strncpy( szDummy, strtok( NULL, ",()\"" ), sizeof( szDummy ) );
+ V_strncpy( szPartName, strtok( NULL, ",()\"" ), sizeof( szPartName ) );
+
+ // Convert to hex from decimal
+ sprintf( szVendorID, "%04x", atoi( szVendorID ) );
+ sprintf( szDeviceID, "%04x", atoi( szDeviceID ) );
+
+ // Example string:
+ // ATI Radeon X600,,,,,,,0x1002,0x3150,0x3150,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ o.Write( szPartName, strlen( szPartName ) );
+ o.Write( ",,,,,,,", 7 );
+ o.Write( "0x", 2 );
+ o.Write( szVendorID, strlen( szVendorID ) );
+ o.Write( ",", 1 );
+ o.Write( "0x", 2 );
+ o.Write( szDeviceID, strlen( szDeviceID ) );
+ o.Write( ",", 1 );
+ o.Write( "0x", 2 );
+ o.Write( szDeviceID, strlen( szDeviceID ) );
+ o.Write( "\n", 1 );
+ }
+ }
+
+ o.Close();
+}
+
+char *CopyTokenUntilComma( char *pOut, char *pIn )
+{
+ if ( !pIn || !pOut )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+
+ while ( ( *pIn != ',' ) && ( *pIn != '\0' ) && ( *pIn != '\n' ) )
+ {
+ *pOut++ = *pIn++;
+ }
+
+ *pOut = '\0';
+
+ return ++pIn; // gobble the comma
+}
+
+
+void ParseDeviceRecord( char *pStr, DeviceRecord_t *deviceRecord )
+{
+ pStr = CopyTokenUntilComma( deviceRecord->szName, pStr );
+
+ for ( int i=0; i<g_nNumDXSupportColumns; i++ ) // Null out the strings
+ {
+ V_strncpy( deviceRecord->szData[i], "", 64 );
+ }
+
+ int i = 0; // Populate the strings
+ while ( *pStr != '\0' )
+ {
+ pStr = CopyTokenUntilComma( deviceRecord->szData[i], pStr );
+ i++;
+ }
+}
+
+// Attempt to merge record nRecord+1 into nRecord
+static bool DidMerge( CUtlVector<DeviceRecord_t> &deviceRecords, int nRecord )
+{
+ // If we have the same name and vendor, we are a merge candidate
+ if ( !V_strnicmp( deviceRecords[nRecord].szName, deviceRecords[nRecord+1].szName, 256 ) &&
+ !V_strnicmp( deviceRecords[nRecord].szData[g_nVendorIDIndex], deviceRecords[nRecord+1].szData[g_nVendorIDIndex], 64 ) )
+ {
+ // Convert hex device ID strings into integers for comparisons
+ int nMinIDCur, nMaxIDCur, nMinIDNext, nMaxIDNext;
+ sscanf( deviceRecords[nRecord].szData[g_nDeviceMinIDIndex], "%x", &nMinIDCur );
+ sscanf( deviceRecords[nRecord].szData[g_nDeviceMaxIDIndex], "%x", &nMaxIDCur );
+ sscanf( deviceRecords[nRecord+1].szData[g_nDeviceMinIDIndex], "%x", &nMinIDNext );
+ sscanf( deviceRecords[nRecord+1].szData[g_nDeviceMaxIDIndex], "%x", &nMaxIDNext );
+
+ // If the ranges overlap or are adjacent, merge the data
+ if ( ( nMinIDNext >= nMinIDCur ) && ( nMinIDNext <= (nMaxIDCur+1) ) )
+ {
+ // Set current max to max of the two ranges, merge other elements and flag next record for deletion
+ V_snprintf( deviceRecords[nRecord].szData[g_nDeviceMaxIDIndex], 64, "0x%04x", MAX( nMaxIDNext, nMaxIDCur ) );
+
+ for( int i=g_nDeviceMaxIDIndex+1; i < g_nNumDXSupportColumns; i++ ) // Run through elements after maxID
+ {
+ if ( strlen( deviceRecords[nRecord+1].szData[i] ) != 0 ) // If the next record has any data in this element
+ {
+ if ( V_strnicmp( deviceRecords[nRecord].szData[i], deviceRecords[nRecord+1].szData[i], 64 ) ) // If it doesn't match the current record's element
+ {
+ if ( strlen( deviceRecords[nRecord].szData[i] ) == 0 ) // If the current record has no data for this entry
+ {
+ V_strncpy( deviceRecords[nRecord].szData[i], deviceRecords[nRecord+1].szData[i], 64 ); // Just copy the merged record's data into current record
+ }
+ else // This is the interesting case, where we have a bona fide conflict
+ {
+ V_strncat( deviceRecords[nRecord].szData[i], " FIXME ", 64 ); // Mark the element with ***
+ V_strncat( deviceRecords[nRecord].szData[i], deviceRecords[nRecord+1].szData[i], 64 ); // Concat the merged element in
+
+ g_bMergeConflict = true;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+// Look for duplicate adjacent entries (same vendorID and min/max, ignoring device name string)
+static bool FoundDuplicate( CUtlVector<DeviceRecord_t> &deviceRecords, int nRecord )
+{
+ // Spew cases with same vendor ID and device min/maxes...these are likely the same device
+ if ( !V_strnicmp( deviceRecords[nRecord].szData[g_nVendorIDIndex], deviceRecords[nRecord + 1].szData[g_nVendorIDIndex], 64 ) )
+ {
+ // Convert hex device ID strings into integers for comparisons
+ int nMinIDCur, nMaxIDCur, nMinIDNext, nMaxIDNext;
+ sscanf( deviceRecords[nRecord].szData[g_nDeviceMinIDIndex], "%x", &nMinIDCur );
+ sscanf( deviceRecords[nRecord].szData[g_nDeviceMaxIDIndex], "%x", &nMaxIDCur );
+ sscanf( deviceRecords[nRecord + 1].szData[g_nDeviceMinIDIndex], "%x", &nMinIDNext );
+ sscanf( deviceRecords[nRecord + 1].szData[g_nDeviceMaxIDIndex], "%x", &nMaxIDNext );
+
+ if ( ( nMinIDCur == nMinIDNext ) && ( nMaxIDCur == nMaxIDNext ) )
+ {
+ printf( "Duplicate: %s %s 0x%04x 0x%04x\n", deviceRecords[nRecord].szName, deviceRecords[nRecord].szData[g_nVendorIDIndex], nMinIDCur, nMaxIDCur );
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void ParseColumnHeadings( char *pHeadings )
+{
+ char *pToken = strtok( pHeadings, "," );
+ int i = 0;
+
+ while ( pToken )
+ {
+ if ( !V_strnicmp( pToken, "VendorID", 64 ) )
+ {
+ g_nVendorIDIndex = i-1;
+ }
+ else if ( !V_strnicmp( pToken, "MinDeviceID", 64 ) )
+ {
+ g_nDeviceMinIDIndex = i-1;
+ }
+ else if ( !V_strnicmp( pToken, "MaxDeviceID", 64 ) )
+ {
+ g_nDeviceMaxIDIndex = i-1;
+ }
+
+ pToken = strtok( NULL, "," );
+ i++;
+ }
+
+ g_nNumDXSupportColumns = i-1;
+
+ Assert( g_nNumDXSupportColumns <= MAX_RECORDS );
+}
+
+
+
+static void CleanCSVFile( char const *pInputFilename, char const *pOutputFilename )
+{
+ CRequiredInputTextFile f( pInputFilename );
+ COutputTextFile o( pOutputFilename );
+ char lineBuffer[4096];
+
+ CUtlVector<DeviceRecord_t> deviceRecords;
+
+ f.ReadLine( lineBuffer, sizeof( lineBuffer ) ); // Pass header line through
+ o.Write( lineBuffer, strlen( lineBuffer ) );
+
+ ParseColumnHeadings( lineBuffer );
+
+ while ( f.ReadLine( lineBuffer, sizeof( lineBuffer ) ) )
+ {
+ if ( V_strlen( lineBuffer ) > 12 ) // Just make sure we have some data
+ {
+ DeviceRecord_t deviceRecord;
+ ParseDeviceRecord( lineBuffer, &deviceRecord );
+
+ // If we have a line with a real device, add it to the vector
+ if ( ( strlen( deviceRecord.szData[g_nVendorIDIndex] ) != 0 ) &&
+ ( strlen( deviceRecord.szData[g_nDeviceMinIDIndex] ) != 0 ) &&
+ ( strlen( deviceRecord.szData[g_nDeviceMaxIDIndex] ) != 0 ) )
+ {
+ deviceRecords.AddToTail( deviceRecord );
+ }
+ else
+ {
+ o.Write( lineBuffer, strlen( lineBuffer ) );
+ }
+ }
+ else
+ {
+ o.Write( lineBuffer, strlen( lineBuffer ) ); // pass short lines through
+ }
+ }
+
+ // At this point, the output file has the header block from the file and we have records for all of the real device lines
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Merge "adjacent" instances of the same device
+ //
+ int i = 0;
+ while( i < deviceRecords.Count() - 1 ) // March through devices, merging
+ {
+ if ( DidMerge( deviceRecords, i ) ) // Did i+1 get merged into i?
+ {
+ deviceRecords.Remove( i+1 ); // Remove i+1 and check with the same i again
+ continue; // don't increment
+ }
+
+ i++; // Move to next record
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Remove duplicate devices (based on deviceID, not name)
+ //
+ i = 0;
+ while ( i < deviceRecords.Count() - 1 ) // March through devices, looking for duplicates
+ {
+ if ( FoundDuplicate( deviceRecords, i ) ) // Does i+1 look like a duplicate of i?
+ {
+ deviceRecords.Remove( i + 1 ); // Remove i+1 and check with the same i again
+ continue; // don't increment
+ }
+
+ i++; // Move to next record
+ }
+
+ // Clean up the hex device ID formatting (pad to 0x1234 with leading zeroes)
+ for ( int i = 0; i< deviceRecords.Count(); i++ )
+ {
+ int nDummy;
+ sscanf( deviceRecords[i].szData[g_nDeviceMinIDIndex], "%x", &nDummy );
+ V_snprintf( deviceRecords[i].szData[g_nDeviceMinIDIndex], 64, "0x%04x", nDummy );
+
+ sscanf( deviceRecords[i].szData[g_nDeviceMaxIDIndex], "%x", &nDummy );
+ V_snprintf( deviceRecords[i].szData[g_nDeviceMaxIDIndex], 64, "0x%04x", nDummy );
+ }
+
+ // Just spray the devices out
+ for ( int i = 0; i< deviceRecords.Count(); i++ )
+ {
+ o.Write( deviceRecords[i].szName, strlen( deviceRecords[i].szName ) );
+ for ( int j=0; j<g_nNumDXSupportColumns; j++ )
+ {
+ o.Write( ",", 1 );
+ o.Write( deviceRecords[i].szData[j], strlen( deviceRecords[i].szData[j] ) );
+ }
+
+ o.Write( "\n", 1 );
+ }
+}
+
+
+void main(int argc,char **argv)
+{
+ InitCommandLineProgram( argc, argv );
+ if ( argc != 5 )
+ {
+ printf( "\n" );
+ printf( " dxsupportclean output depends on the input file type (.csv or not).\n" );
+ printf( " The output is always a CSV file.\n\n" );
+ printf( " usage: dxsupportclean -i <inputfile> -o <outputfile.csv>\n" );
+ printf( " If the input file is not csv, dxsupportclean expects hardware\n" );
+ printf( " survey php syntax. If the input file is csv, dxsupportclean expects\n" );
+ printf( " the first line to contain specific header columns.\n" );
+ printf( " If you want to provide some other type of input or if you modify the\n" );
+ printf( " header columns in dxsupport, you'll have to modify dxsupportclean.\n" );
+ return;
+ }
+
+ const char *pInputFile = CommandLine()->ParmValue( "-i" );
+ const char *pOutputFile = CommandLine()->ParmValue( "-o" );
+
+ // Can't input and output the same file
+ if ( !V_strnicmp( pInputFile, pOutputFile, MAX_PATH ) )
+ {
+ printf( "Input and out files must not be the same file! No output produced.\n" );
+ return;
+ }
+
+ if ( !stricmp( "csv", Q_GetFileExtension( pInputFile ) ) )
+ {
+ CleanCSVFile( pInputFile, pOutputFile );
+
+ if ( g_bMergeConflict )
+ {
+ printf( "\n*************************************************************************\n" );
+ printf( " Merge Conflict detected. Search output for FIXME and resolve manually!\n" );
+ printf( "*************************************************************************\n\n" );
+ }
+ }
+ else
+ {
+ GrabSurveyData( pInputFile, pOutputFile );
+ }
+}
diff --git a/utils/dxsupportclean/dxsupportclean.vpc b/utils/dxsupportclean/dxsupportclean.vpc
new file mode 100644
index 0000000..d51f43e
--- /dev/null
+++ b/utils/dxsupportclean/dxsupportclean.vpc
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------------
+// DXSUPPORTCLEAN.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+// ***** AUTO-GENERATED: PLEASE FIXUP MANUALLY BEFORE USING THIS SCRIPT! *****
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,..\common"
+ }
+}
+
+$Project "dxsupportclean"
+{
+ $Folder "Source Files"
+ {
+ -$File "$SRCDIR\public\tier0\memoverride.cpp"
+ $File "dxsupportclean.cpp"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib mathlib
+ $Lib tier2
+ }
+}
+
+
+