|
|
use strict; no strict 'refs';
###################################################### # Data Section ######################################################
my(@lines) = (); # holds the input file my(@tabs) = (); # for indentation my(@lineToPrint) = (); # current formatted output line #my(@configOutput) = (); # output from configuration parsing my(%configOutput) = (); # hash of configuration-specific config options my($currentConfig) = ""; # configuration currently being parsed my($nameFound) = 0; # flag set when project name has been parsed my($lineCt) = 0; # current line number in the source file my($exclusionsFound) = 0; # an file has been 'excluded from build' for some configuration my($projectName) = ""; # base name of the project my($parsingFiles) = 0; # a cheap state variable my($splitConfigs) = 0; # debug variable set from the commmand line my($outputPath) = undef;# optional path for the vpc destination my($spaceBeforeFolder) = 0; # tracks when to add a line before folder blocks my($spaceBeforeFile) = 0; # tracks when to add a line before file blocks my($tabstop) = 4; # size of tabs - 4 for visual studio my($srcdirBackslash) = undef;# holds the value of the macro SRCDIR, with \ separators my($srcdirForwardslash) = undef;# holds the value of the macro SRCDIR, with / separators
my($usestring) = 1; # use string values for compiler options my($stripEmptyOptions) = 1; # remove compiler options that have empty values (strings) if ( $ARGV[1] =~ /useindex/ ) { $usestring = 0; } elsif ( $ARGV[1] =~ /allownullstrings/ ) { $stripEmptyOptions = 0; } elsif ( $ARGV[1] =~ /-o/ ) { $outputPath = $ARGV[2]; }
############################################################################## # Match vcproj option keywords with vpc keywords - only string or yes/no value options # String on the left matches the option name in the VCProj. # String on the right matches the option name in vpc
my(%configOptionsSingleValue) = (
# Configuration "General" => { # General "OutputDirectory" => "OutputDirectory", "IntermediateDirectory" => "IntermediateDirectory", "DeleteExtensionsOnClean" => "ExtensionsToDeleteOnClean", "BrowseInformation" => "BuildBrowserInformation", "ATLMinimizesCRunTimeLibraryUsage" => "MinimizeCRTUseInATL", "ManagedExtensions" => "UseManagedExtensions", "WholeProgramOptimization" => "WholeProgramOptimization", "ReferencesPath" => "ReferencesPath", "ExcludedFromBuild" => "ExcludedFromBuild",
# Debugging },
# C/C++ "VCCLCompilerTool" => { # General "AdditionalIncludeDirectories" => "AdditionalIncludeDirectories", "AdditionalUsingDirectories" => "ResolveUsingReferences", "WarningLevel" => "WarningLevel",
# Optimization # Preprocessor "PreprocessorDefinitions" => "PreprocessorDefinitions",
# Code Generation
# Language
# Precompiled Headers "PrecompiledHeaderThrough" => "Create/UsePCHThroughFile", "PrecompiledHeaderFile" => "PrecompiledHeaderFile",
# Output Files "AssemblerListingLocation" => "ASMListLocation", "ObjectFile" => "ObjectFileName", "ProgramDataBaseFileName" => "ProgramDatabaseFileName",
# Browse Information "BrowseInformationFile" => "BrowseFile",
# Advanced "DisableSpecificWarnings" => "DisableSpecificWarnings", "ForcedIncludeFiles" => "ForceIncludes", "ForcedUsingFiles" => "ForceUsing", "UndefinePreprocessorDefinitions" => "UndefinePreprocessorDefinitions",
# Command Line "AdditionalOptions" => "AdditionalOptions", },
# Librarian "VCLibrarianTool" => { # General "OutputFile" => "ResourceOutputFileName", "AdditionalDependencies" => "AdditionalDependencies", "AdditionalLibraryDirectories" => "AdditionalLibraryDirectories", "ModuleDefinitionFile" => "ModuleDefinitionFileName", "IgnoreDefaultLibraryNames" => "IgnoreSpecificLibrary", "ExportNamedFunctions" => "ExportNamedFunctions", "ForceSymbolReferences" => "ForceSymbolReferences",
# Command LIne "AdditionalOptions" => "AdditionalOptions", },
# Linker "VCLinkerTool" => { # General "OutputFile" => "OutputFile", "Version" => "Version", "IgnoreImportLibrary" => "IgnoreImportLibrary", "RegisterOutput" => "RegisterOutput", "AdditionalLibraryDirectories" => "AdditionalLibraryDirectories",
# Input "AdditionalDependencies" => "AdditionalDependencies", "IgnoreDefaultLibraryNames" => "IgnoreSpecificLibrary", "ModuleDefinitionFile" => "ModuleDefinitionFile", "AddModuleNamesToAssembly" => "AddModuleToAssembly", "EmbedManagedResourceFile" => "EmbedManagedResourceFile", "ForceSymbolReferences" => "ForceSymbolReferences", "DelayLoadDLLs" => "DelayLoadedDLLs",
# Debugging "ProgramDatabaseFile" => "GenerateProgramDatabaseFile", "StripPrivateSymbols" => "StripPrivateSymbols", "MapFileName" => "MapFileName", # System "HeapReserveSize" => "HeapReserverSize", "HeapCommitSize" => "HeapCommitSize", "StackReserveSize" => "StackReserveSize", "StackCommitSize" => "StackCommitSize",
# Optimization "FunctionOrder" => "FunctionOrder",
# Embedded IDL "MidlCommandFile" => "MIDLCommands", "MergedIDLBaseFileName" => "MergedIDLBaseFileName", "TypeLibraryFile" => "TypeLibrary", "TypeLibraryResourceID" => "TypeLibResourceID",
# Advanced "EntryPointSymbol" => "EntryPoint", "BaseAddress" => "BaseAddress", "ImportLibrary" => "ImportLibrary", "MergeSections" => "MergeSections",
# Command LIne "AdditionalOptions" => "AdditionalOptions", },
# Resources "VCResourceCompilerTool" => { # General "PreprocessorDefinitions" => "PreprocessorDefinitions", "AdditionalIncludeDirectories" => "AdditionalIncludeDirectories", "ResourceOutputFileName" => "ResourceOutputFileName",
# Command LIne "AdditionalOptions" => "AdditionalOptions", },
# Build Events "VCPreBuildEventTool" => { # Pre-Build Event "CommandLine" => "CommandLine", "Description" => "Description", "ExcludedFromBuild" => "ExcludedFromBuild", },
"VCPreLinkEventTool" => { # Pre-Link Event "CommandLine" => "CommandLine", "Description" => "Description", "ExcludedFromBuild" => "ExcludedFromBuild", },
"VCPostBuildEventTool" => { # Post-Build Event "CommandLine" => "CommandLine", "Description" => "Description", "ExcludedFromBuild" => "ExcludedFromBuild", },
# Custom Build Step "VCCustomBuildTool" => { # Pre-Build Event "CommandLine" => "CommandLine", "Description" => "Description", "Outputs" => "Outputs", "AdditionalDependencies" => "AdditionalDependencies", },
);
############################################################################## # Match vcproj option keywords with vpc keywords - only multi-value options # String on the left matches the option name in the VCProj. # String on the right matches the option name in vpc
my(%configOptionsMultiValue) = (
# General "ConfigurationType" => "ConfigurationType", "UseOfMFC" => "UseOfMFC", "UseOfAtl" => "UseOfATL", "CharacterSet" => "CharacterSet",
# Debugging
# C/C++ # General "DebugInformationFormat" => "DebugInformationFormat", "SuppressStartupBanner" => "SuppressStartupBanner", "Detect64BitPortabilityProblems" => "Detect64BitPortabilityIssues", "WarnAsError" => "TreatWarningsAsErrors",
# Optimization "Optimization" => "Optimization", "GlobalOptimizations" => "GlobalOptimizations", "InlineFunctionExpansion" => "InlineFunctionExpansion", "EnableIntrinsicFunctions" => "EnableIntrinsicFunctions", "ImproveFloatingPointConsistency" => "FloatingPointConsistency", "FavorSizeOrSpeed" => "FavorSizeOrSpeed", "OmitFramePointers" => "OmitFramePointers", "EnableFiberSafeOptimizations" => "EnableFiberSafeOptimizations", "OptimizeForProcessor" => "OptimizeForProcessor", "OptimizeForWindowsApplication" => "OptimizeForWindowsApplication", "WholeProgramOptimization" => "WholeProgramOptimization", # Preprocessor "IgnoreStandardIncludePath" => "IgnoreStandardIncludePath", "GeneratePreprocessedFile" => "GeneratePreprocessedFile", "KeepComments" => "KeepComments",
# Code Generation "StringPooling" => "EnableStringPooling", "MinimalRebuild" => "EnableMinimalRebuild", "ExceptionHandling" => "EnableC++Exceptions", "SmallerTypeCheck" => "SmallerTypeCheck", "BasicRuntimeChecks" => "BasicRuntimeChecks", "RuntimeLibrary" => "RuntimeLibrary", "StructMemberAlignment" => "StructMemberAlignement", "BufferSecurityCheck" => "BufferSecurityCheck", "EnableFunctionLevelLinking" => "EnableFunctionLevelLinking", "EnableEnhancedInstructionSet" => "EnableEnhancedInstructionSet",
# Language "DisableLanguageExtensions" => "DisableLanguageExtensions", "DefaultCharIsUnsigned" => "DefaultCharUnsigned", "TreatWChar_tAsBuiltInType" => "TreatWchar_tAsBuiltinType", "ForceConformanceInForLoopScope" => "ForceConformanceInForLoopScope", "RuntimeTypeInfo" => "EnableRunTimeTypeInfo",
# Precompiled Headers "UsePrecompiledHeader" => "Create/UsePrecompiledHeader",
# Output Files "ExpandAttributedSource" => "ExpandAttributedSource", "AssemblerOutput" => "AssemblerOutput",
# Browse Information "BrowseInformation" => "EnableBrowseInformation",
# Advanced "CallingConvention" => "CallingConvention", "CompileAs" => "CompileAs", "UndefineAllPreprocessorDefinitions" => "UndefineAllPreprocessorDefinitions",
# Librarian # General "SuppressStartupBanner" => "SuppressStartupBanner", "IgnoreAllDefaultLibraries" => "IgnoreAllDefaultLibraries", # Linker # General "ShowProgress" => "ShowProgress", "LinkIncremental" => "EnableIncrementalLinking", "SuppressStartupBanner" => "SuppressStartupBanner",
# Linker "IgnoreAllDefaultLibraries" => "IgnoreAllDefaultLibraries",
# Debugging "GenerateDebugInformation" => "GenerateDebugInfo", "AssemblyDebug" => "DebuggableAssembly", "GenerateMapFile" => "GenerateMapFile", "MapExports" => "MapExports", "MapLines" => "MapLines",
# System "SubSystem" => "SubSystem", "LargeAddressAware" => "EnableLargeAddresses", "TerminalServerAware" => "TerminalServer", "SwapRunFromCD" => "SwapRunFromCD", "SwapRunFromNet" => "SwapRunFromNetwork",
# Optimization "OptimizeReferences" => "References", "EnableCOMDATFolding" => "EnableCOMDATFolding", "OptimizeForWindows98" => "OptimizeForWindows98",
# Embedded IDL "IgnoreEmbeddedIDL" => "IgnoreEmbeddedIDL",
# Advanced "ResourceOnlyDLL" => "ResourceOnlyDLL", "SetChecksum" => "SetChecksum", "FixedBaseAddress" => "FixedBaseAddress", "TurnOffAssemblyGeneration" => "TurnOffAssemblyGeneration", "SupportUnloadOfDelayLoadedDLL" => "DelayLoadedDLL", "TargetMachine" => "TargetMachine",
# Resources # General "Culture" => "Culture", "IgnoreStandardIncludePath" => "IgnoreStandardIncludePath", "ShowProgress" => "ShowProgress", );
############################################################################## # Match user option names to their lists of possible values
my(%configOptionValues) = (
# General "ConfigurationType" => { "0" => "Makefile", "1" => "Application \(\.exe\)", "2" => "Dynamic Library \(\.dll\)", "3" => "Static Library \(\.lib\)", "4" => "Utility", }, "UseOfMFC" => { "0" => "Use Standard Windows Libraries", "1" => "Use MFC In A Static Library", "2" => "Use MFC In A Shared DLL", }, "UseOfATL" => { "0" => "Not Using ATL", "1" => "Static Link To ATL", "2" => "Dynamic Link To ATL", }, "CharacterSet" => { "0" => "Not Set", "1" => "Use Unicode Character Set", "2" => "Use Multi-Byte Character Set", },
# Debugging
# C/C++ # General "DebugInformationFormat" => { "0" => "Disabled", "1" => "C7 Compatible \(\/Z7\)", "2" => "Line Numbers Only \(\/Zd\)", "3" => "Program Database \(\/Zi\)", "4" => "Program Database for Edit & Continue \(\/ZI\)", }, "SuppressStartupBanner" => { "FALSE" => "No", "TRUE" => "Yes (/nologo)", }, "Detect64BitPortabilityProblems" => { "FALSE" => "No", "TRUE" => "Yes (/Wp64)", }, "WarnAsError" => { "FALSE" => "No", "TRUE" => "Yes (/WX)", },
# Optimization "Optimization" => { "0" => "Disabled \(\/Od\)", "1" => "Minimize Size \(\/O1\)", "2" => "Maximize Speed \(\/O2\)", "3" => "Full Optimization \(\/Ox\)", "4" => "Custom", }, "GlobalOptimizations" => { "FALSE" => "No", "TRUE" => "Yes (/Og)", }, "InlineFunctionExpansion" => { "0" => "Default", "1" => "Only __inline \(\/Ob1\)", "2" => "Any Suitable \(\/Ob2\)", }, "EnableIntrinsicFunctions" => { "FALSE" => "No", "TRUE" => "Yes (/Oi)", }, "ImproveFloatingPointConsistency" => { "FALSE" => "Default Consistency", "TRUE" => "Improve Consistency \(\/Op\)", }, "FavorSizeOrSpeed" => { "0" => "Neither", "1" => "Favor Fast Code \(\/Ot\)", "2" => "Favor Small Code \(\/Os\)", }, "OmitFramePointers" => { "FALSE" => "No", "TRUE" => "Yes (/Oy)", }, "EnableFiberSafeOptimizations" => { "FALSE" => "No", "TRUE" => "Yes (/GT)", }, "OptimizeForProcessor" => { "0" => "Blended", "1" => "Pentium \(\/G5\)", "2" => "Pentium Pro, Pentium II, Pentium III \(\/G6\)", "3" => "Pentium 4 and Above \(\/G7\)", }, "OptimizeForWindowsApplication" => { "FALSE" => "No", "TRUE" => "Yes (/GA)", }, "WholeProgramOptimization" => { "FALSE" => "No", "TRUE" => "Enable link-time code generation (/GL)", },
# Preprocessor "IgnoreStandardIncludePath" => { "FALSE" => "No", "TRUE" => "Yes (/X)", }, "GeneratePreprocessedFile" => { "0" => "No", "1" => "With Line Numbers \(\/P\)", "2" => "Without Line Numbers \(\/EP \/P\)", }, "KeepComments" => { "FALSE" => "No", "TRUE" => "Yes (/C)", },
# Code Generation "StringPooling" => { "FALSE" => "No", "TRUE" => "Yes (/GF)", }, "MinimalRebuild" => { "FALSE" => "No", "TRUE" => "Yes (/Gm)", }, "ExceptionHandling" => { "FALSE" => "No", "TRUE" => "Yes (/EHsc)", }, "SmallerTypeCheck" => { "FALSE" => "No", "TRUE" => "Yes (/RTCc)", }, "BasicRuntimeChecks" => { "0" => "Default", "1" => "Stack Frames \(\/RTCs\)", "2" => "Uninitialized Variables \(\/RTCu\)", "3" => "Both \(\/RTC1, equiv\. to \/RTCsu\)", }, "RuntimeLibrary" => { "0" => "Multi-threaded \(\/MT\)", "1" => "Multi-threaded Debug \(\/MTd\)", "2" => "Multi-threaded DLL \(\/MD\)", "3" => "Multi-threaded Debug DLL \(\/MDd\)", "4" => "Single-threaded \(\/ML\)", "5" => "Single-threaded Debug \(\/MLd\)", }, "StructMemberAlignment" => { "0" => "Default", "1" => "1 Byte \(\/Zp1\)", "2" => "2 Bytes \(\/Zp2\)", "3" => "4 Bytes \(\/Zp4\)", "4" => "8 Bytes \(\/Zp8\)", "5" => "16 Bytes \(\/Zp16\)", }, "BufferSecurityCheck" => { "FALSE" => "No", "TRUE" => "Yes (/Gs)", }, "EnableFunctionLevelLinking" => { "FALSE" => "No", "TRUE" => "Yes (/Gy)", }, "EnableEnhancedInstructionSet" => { "0" => "Not Set", "1" => "Streaming SIMD Extensions \(\/arch:SSE\)", "2" => "Streaming SIMD Extensions 2 \(\/arch:SSE2\)", },
# Language "DisableLanguageExtensions" => { "FALSE" => "No", "TRUE" => "Yes (/Za)", }, "DefaultCharIsUnsigned" => { "FALSE" => "No", "TRUE" => "Yes (/J)", }, "TreatWChar_tAsBuiltInType" => { "FALSE" => "No", "TRUE" => "Yes (/Zc:wchar_t)", }, "ForceConformanceInForLoopScope" => { "FALSE" => "No", "TRUE" => "Yes (/Zc:forScope)", }, "RuntimeTypeInfo" => { "FALSE" => "No", "TRUE" => "Yes (/GR)", },
# Precompiled Headers "UsePrecompiledHeader" => { "0" => "Not Using Precompiled Headers", "1" => "Create Precompiled Header \(\/Yc\)", "2" => "Automatically Generate \(\/YX\)", "3" => "Use Precompiled Header \(\/Yu\)", },
# Output Files "ExpandAttributedSource" => { "FALSE" => "No", "TRUE" => "Yes (/Fx)", }, "AssemblerOutput" => { "0" => "No Listing", "1" => "Assembly-Only Listing \(\/FA\)", "2" => "Assembly, Machine Code and Source \(\/FAcs\)", "3" => "Assembly With Machine Code \(\/FAc\)", "4" => "Assembly With Source Code \(\/FAs\)", },
# Browse Information "BrowseInformation" => { "0" => "None", "1" => "Include All Browse Information \(\/FR\)", "2" => "No Local Symbols \(\/Fr\)", },
# Advanced "CallingConvention" => { "0" => "__cdecl \(\/Gd\)", "1" => "__fastcall \(\/Gr\)", "2" => "__stdcall \(\/Gz\)", }, "CompileAs" => { "0" => "Default", "1" => "Compile as C Code \(\/TC\)", "2" => "Compile as C\+\+ Code \(\/TP\)", }, "UndefineAllPreprocessorDefinitions" => { "FALSE" => "No", "TRUE" => "Yes (/u)", },
# Librarian # General "SuppressStartupBanner" => { "FALSE" => "No", "TRUE" => "Yes (/NOLOGO)", }, "IgnoreAllDefaultLibraries" => { "FALSE" => "No", "TRUE" => "Yes (/NODEFAULTLIB)", },
# Linker #General "ShowProgress" => { "0" => "Not Set", "1" => "Display All Progress Messages \(\/VERBOSE\)", "2" => "Displays Some Progress Messages \(\/VERBOSE:LIB\)", }, "LinkIncremental" => { "0" => "Default", "1" => "No \(\/INCREMENTAL:NO\)", "2" => "Yes \(\/INCREMENTAL\)", }, "SuppressStartupBanner" => { "FALSE" => "No", "TRUE" => "Yes (/NOLOGO)", },
# Linker "IgnoreAllDefaultLibraries" => { "FALSE" => "No", "TRUE" => "Yes (/NODEFAULTLIB)", },
# Debugging "GenerateDebugInformation" => { "FALSE" => "No", "TRUE" => "Yes (/DEBUG)", }, "AssemblyDebug" => { "0" => "No Debuggable attribute emitted", "1" => "Runtime tracking and disable optimizations \(\/ASSEMBLYDEBUG\)", "2" => "No runtime tracking and enable optimizations \(\/ASSEMBLYDEBUG:DISABLE\)", }, "GenerateMapFile" => { "FALSE" => "No", "TRUE" => "Yes (/MAP)", }, "MapExports" => { "FALSE" => "No", "TRUE" => "Yes (/MAPINFO:EXPORTS)", }, "MapLines" => { "FALSE" => "No", "TRUE" => "Yes (/MAPINFO:LINES)", },
# System "SubSystem" => { "0" => "Not Set", "1" => "Console \(\/SUBSYSTEM:CONSOLE\)", "2" => "Windows \(\/SUBSYSTEM:WINDOWS\)", }, "LargeAddressesAware" => { "0" => "Default", "1" => "Do Not Support Addresses Larger Than 2 Gigabytes \(\/LARGEADDRESSAWARE:NO\)", "2" => "Support Addresses Larger Than 2 Gigabytes \(\/LARGEADDRESSAWARE\)", }, "TerminalServerAware" => { "0" => "Default", "1" => "Not Terminal Server Aware \(\/TSAWARE:NO\)", "2" => "Application is Terminal Server Aware \(\/TSAWARE\)", }, "SwapRunFromCD" => { "FALSE" => "No", "TRUE" => "Yes (/SWAPRUN:CD)", }, "SwapRunFromNet" => { "FALSE" => "No", "TRUE" => "Yes (/SWAPRUN:NET)", },
#Optimization "OptimizeReferences" => { "0" => "Default", "1" => "Keep Unreferenced Data \(\/OPT:NOREF\)", "2" => "Eliminate Unreferenced Data \(\/OPT:REF\)", }, "EnableCOMDATFolding" => { "0" => "Default", "1" => "Do Not Remove Redundant COMDATs \(\/OPT:NOICF\)", "2" => "Remove Redundant COMDATs \(\/OPT:ICF\)", }, "OptimizeForWindows98" => { "0" => "Default", "1" => "No \(\/OPT:NOWIN98\)", "2" => "Yes \(\/OPT:WIN98\)", },
# Embedded IDL "IgnoreEmbeddedIDL" => { "FALSE" => "No", "TRUE" => "Yes (/IGNOREIDL)", },
#Advanced "ResourceOnlyDLL" => { "FALSE" => "No", "TRUE" => "Yes (/NOENTRY)", }, "SetChecksum" => { "FALSE" => "No", "TRUE" => "Yes (/RELEASE)", }, "FixedBaseAddress" => { "0" => "Default", "1" => "Generate a relocation section \(\/FIXED:NO\)", "2" => "Image must be loaded at a fixed address \(\/FIXED\)", }, "TurnOffAssemblyGeneration" => { "FALSE" => "No", "TRUE" => "Yes (/NOASSEMBLY)", }, "SupportUnloadOfDelayLoadedDLL" => { "0" => "Don't Support Unload", "1" => "Support Unload \(\/DELAY:UNLOAD\)", }, "TargetMachine" => { "0" => "Not Set", "1" => "MachineX86 \(\/MACHINE:X86\)", },
# Resources # General "Culture" => "Culture", { "1000" => "Default", "1001" => "Afrikaans \(0x436\)", "1002" => "Albanian \(0x41c\)", "1003" => "Arabic (Saudi Arabia) \(0x401\)", "1004" => "Arabic (Iraq) \(0x801\)", "1005" => "Arabic (Egypt) \(0xc01\)", "1006" => "Arabic (Libya) \(0x1001\)", "1007" => "Arabic (Algeria) \(0x1401\)", "1008" => "Arabic (Morocco) \(0x1801\)", "1009" => "Arabic (Tunisia) \(0x1c01\)", "1010" => "Arabic (Oman) \(0x2001\)", "1011" => "Arabic (Yemen) \(0x2401\)", "1012" => "Arabic (Syria) \(0x2801\)", "1013" => "Arabic (Jordan) \(0x2c01\)", "1014" => "Arabic (Lebanon) \(0x3001\)", "1015" => "Arabic (Kuwait) \(0x3401\)", "1016" => "Arabic (U.A.E.) \(0x3801\)", "1017" => "Arabic (Bahrain) \(0x3c01\)", "1018" => "Arabic (Qatar) \(0x4001\)", "1019" => "Basque \(0x42d\)", "1020" => "Bulgarian \(0x402\)", "1021" => "Belarusian \(0x423\)", "1022" => "Catalan \(0x403\)", "1023" => "Chinese (Taiwan) \(0x404\)", "1024" => "Chinese (PRC) \(0x804\)", "1025" => "Chinese (Hong Kong S.A.R.) \(0xc04\)", "1026" => "Chinese (Singapore) \(0x1004\)", "1027" => "Croatian \(0x41a\)", "1028" => "Czech \(0x405\)", "1029" => "Danish \(0x406\)", "1030" => "Dutch (Netherlands) \(0x413\)", "1031" => "Dutch (Belgium) \(0x813\)", "1032" => "English (United States) \(0x409\)", "1033" => "English (United Kingdom) \(0x809\)", "1034" => "English (Australia) \(0xc09\)", "1035" => "English (Canada) \(0x1009\)", "1036" => "English (New Zealand) \(0x1409\)", "1037" => "English (Ireland) \(0x1809\)", "1038" => "English (South Africa) \(0x1c09\)", "1039" => "English (Jamaica) \(0x2009\)", "1040" => "English (Caribbean) \(0x2409\)", "1041" => "Estonian \(0x425\)", "1042" => "Farsi \(0x429\)", "1043" => "Finnish \(0x40b)", "1044" => "French (France) \(0x40c\)", "1045" => "French (Belgium) \(0x80c\)", "1046" => "French (Canada) \(0xc0c\)", "1047" => "French (Switzerland) \(0x100c\)", "1048" => "French (Luxembourg) \(0x140c\)", "1049" => "German (Germany) \(0x407\)", "1050" => "German (Switzerland) \(0x807\)", "1051" => "German (Austria) \(0xc07\)", "1052" => "German (Luxembourg) \(0x1007\)", "1053" => "German (Liechtenstein) \(0x1407\)", "1054" => "Greek \(0x408\)", "1055" => "Hebrew \(0x40d\)", "1056" => "Hungarian \(0x40e\)", "1057" => "Icelandic \(0x40f\)", "1058" => "Indonesian \(0x421\)", "1059" => "Italian (Italy) \(0x410\)", "1060" => "Italian (Switzerland) \(0x810\)", "1061" => "Japanese \(0x411\)", "1062" => "Korean \(0x412\)", "1063" => "0x812", "1064" => "Latvian \(0x426\)", "1065" => "Lithuanian \(0x427\)", "1066" => "Norwegian (Bokmal) \(0x414\)", "1067" => "Norwegian (Nynorsk) \(0x814\)", "1068" => "Polish \(0x415\)", "1069" => "Portuguese (Brazil) \(0x416\)", "1070" => "Portuguese (Portugal) \(0x816\)", "1071" => "Romanian \(0x418\)", "1072" => "Russian \(0x419\)", "1073" => "Slovak \(0x41b\)", "1074" => "Spanish (Traditional Sort) \(0x40a\)", "1075" => "Spanish (Mexico) \(0x80a\)", "1076" => "Spanish (International Sort) \(0xc0a\)", "1077" => "Spanish (Guatemala) \(0x100a\)", "1078" => "Spanish (Costa Rica) \(0x140a\)", "1079" => "Spanish (Panama) \(0x180a\)", "1080" => "Spanish (Dominican Republic) \(0x1c0a\)", "1081" => "Spanish (Venezuela) \(0x200a\)", "1082" => "Spanish (Colombia) \(0x240a\)", "1083" => "Spanish (Peru) \(0x280a\)", "1084" => "Spanish (Argentina) \(0x2c0a\)", "1085" => "Spanish (Ecuador) \(0x300a\)", "1086" => "Spanish (Chile) \(0x340a\)", "1087" => "Spanish (Uruguay) \(0x380a\)", "1088" => "Spanish (Paraguay) \(0x3c0a\)", "1089" => "Spanish (Bolivia) \(0x400a\)", "1090" => "Swedish \(0x41d\)", "1091" => "Thai \(0x41e\)", "1092" => "Turkish \(0x41f\)", "1093" => "Ukrainian \(0x422\)", "1094" => "Serbian (Latin) \(0x81a\)", "1095" => "Urdu \(0x420\)", }, "IgnoreStandardIncludePath" => "IgnoreStandardIncludePath", { "1" => "No", "2" => "Yes \(\/X\)", }, "ShowProgress" => "ShowProgress", { "1" => "No", "2" => "Yes \(\/v\)", }, );
# Hash matches vcproj configuration names with their output versions my(%configurationNames) = ( "Base" => "base", "DoD" => "dod", "CounterStrike" => "cstrike", "HL1" => "hl1", "HL2" => "hl2", "Episodic HL2" => "episodic", "TF" => "tf", "SDK" => "sdk", "HL2MP" => "hl2mp", "LostCoast" => "lostcoast", "Portal" => "portal", "Dedicated" => "dedicated", ); my(@configurations) = keys %configurationNames;
my(%toolNames) = ( "VCCLCompilerTool" => "Compiler", "VCCustomBuildTool" => "CustomBuildStep", "VCLinkerTool" => "Linker", "VCPostBuildEventTool" => "PostBuildEvent", "VCPreBuildEventTool" => "PreBuildEvent", "VCPreLinkEventTool" => "PreLinkEvent", "VCResourceCompilerTool" => "Resources", "VCLibrarianTool" => "Librarian", ); my(@tools) = values %toolNames;
my($baseConfiguration) = "Application (.exe)"; my(%baseConfigurationTypes) = ( "Dynamic Library (.dll)" => "dll", "Application (.exe)" => "exe", "Static Library (.lib)" => "lib", "Utility" => "lib", );
my($configurationSubsystem) = "con";
my(%outputs); my(%excludes); my(%filesAdded);
for ( @configurations ) { $outputs{$_} = (); $excludes{$_} = 0; $filesAdded{$_} = 0; }
my(%keytabs) = ( 0 => "\t\t\t\t\t\t\t\t\t\t", 4 => "\t\t\t\t\t\t\t\t\t", 8 => "\t\t\t\t\t\t\t\t", 12 => "\t\t\t\t\t\t\t", 16 => "\t\t\t\t\t\t", 20 => "\t\t\t\t\t", 24 => "\t\t\t\t", 28 => "\t\t\t", 32 => "\t\t", 36 => "\t", );
###################################################### # Subroutines ######################################################
sub break { return; }
sub outputToAllConfigurations { for ( @configurations ) { push( @{ $outputs{$_} }, @lineToPrint ); } }
sub compare_arrays { my ($first, $second) = @_; return 0 unless @$first == @$second; for (my $i = 0; $i < @$first; $i++) { if ( $first->[$i] =~ /^(Debug|Release)$/ ) { next; } return 0 if $first->[$i] ne $second->[$i]; } return 1; }
sub set_current_configuration { my($line) = shift;
$line =~ ( /Name="(\w+) ([\w\s]*)\|/ ); my($name1) = $1; my($name2) = $2; if ( $name2 =~ /Release|Debug/ ) { $currentConfig = $name1; } else { $currentConfig = $name2; }
if ( $line =~ ( /Name="(Release|Debug)\|/ ) ) { # default configurations $currentConfig = "Base"; } }
#################################################### sub processFileConfig { $spaceBeforeFile = 1;
my($splitFiles) = 0; my($line) = $_[++$lineCt];
# Set the current configuration
set_current_configuration( $line );
push( @tabs, "\t" );
$line =~ ( /Name="([\w\s]*)\|/ ); my($configName) = ( $1 =~ /(Debug|Release)/ ); push( @{ $configOutput{$currentConfig} }, @tabs, "\$Configuration\t\"", $configName, "\"\n" ); push( @{ $configOutput{$currentConfig} }, @tabs, "\{\n" );
# Process the configuration
my($configResult) = processConfiguration( @_ );
# end if this configuration push( @{ $configOutput{$currentConfig} }, @tabs, "\}\n" );
if ( $configResult == 1 ) { # Mark this file as excluded for the current configuration $excludes{$currentConfig} = 1; $splitFiles = 1; } elsif ( $configResult == -1 ) { # Configuration is empty, so clear it
@{ $configOutput{$currentConfig} } = (); }
pop( @tabs ); return $splitFiles; }
#################################################### sub processFile { # get the file name and path
@lineToPrint = (); if ( $spaceBeforeFile == 1 ) { $spaceBeforeFile = 0; # push( @lineToPrint, "\n" ); }
$_[++$lineCt] =~ ( /RelativePath="([^"]+)"/ ); my $line = $1;
# replace ..\ and .\ in filenames $line =~ s/^\Q$srcdirBackslash\E\\/\$SRCDIR\\/; $line =~ s/^\Q$srcdirForwardslash\E\//\$SRCDIR\\/; $line =~ s/^\.\\//;
push( @lineToPrint, @tabs, "\t\$File\t\"", $line, "\"\n" );
push( @tabs, "\t" );
my($splitFiles) = 0; my($configFound) = 0;
# loop until the </File> tag
%configOutput = (); while ( $_[++$lineCt] !~ /^\s*\<\/File\>$/ ) { # Check for file specific configurations if ( $_[$lineCt] =~ /^\s*\<FileConfiguration/ ) { $configFound = 1; $splitFiles += processFileConfig( @_ ); } } # Compare the configurations to see if the files should be split if ( $configFound && !$splitFiles ) { for ( @configurations ) { if ( $_ eq "Base" || $_ eq "Dedicated" ) { next; } if ( !compare_arrays( \@{ $configOutput{"HL2"} }, \@{ $configOutput{$_} } ) ) { $splitFiles = 1; last; } } if ( !$splitFiles ) { push( @{ $configOutput{"Base"} }, @{ $configOutput{"HL2"} } ); } } # Add the file and configuration to the appropriate projects if ( !$splitFiles ) { if ( @{ $configOutput{"Base"} } > 0 ) { push( @{ $outputs{"Base"} }, @lineToPrint, @tabs, "\{\n" ); push( @{ $outputs{"Base"} }, @{ $configOutput{"Base"} } ); push( @{ $outputs{"Base"} }, @tabs, "\}\n\n" ); } else { push( @{ $outputs{"Base"} }, @lineToPrint ); } $filesAdded{"Base"} = 1; } else { $excludes{"Base"} = 1; $exclusionsFound = 1; for ( @configurations ) { if ( !$excludes{$_} ) { if ( @{ $configOutput{$_} } > 0 ) { push( @{ $outputs{$_} }, @lineToPrint, @tabs, "\{\n" ); push( @{ $outputs{$_} }, @{ $configOutput{$_} } ); push( @{ $outputs{$_} }, @tabs, "\}\n\n" ); } else { push( @{ $outputs{$_} }, @lineToPrint ); } $filesAdded{$_} = 1; } else { # reset the exclude flag $excludes{$_} = 0; } } }
pop( @tabs ); }
#################################################### sub processFolder { push( @tabs, "\t" );
# Grab the folder name and add it to all configuration's outputs
$_[++$lineCt] =~ ( /Name="([^"]+)"/ );
@lineToPrint = ( @tabs, "\$Folder\t\"", $1, "\"\n", @tabs, "\{\n" ); outputToAllConfigurations();
# Loop until the </Filter> tag
while ( $_[++$lineCt] !~ /^\s*\<\/Filter\>$/ ) { if ( $_[$lineCt] =~ /^\s*\<Filter$/ ) { # Start of a new folder
if ( $spaceBeforeFolder == 1 ) { $spaceBeforeFolder = 0; @lineToPrint = "\n"; outputToAllConfigurations(); } processFolder( @_ ); } elsif ( $_[$lineCt] =~ /^\s*\<File$/ ) { # Start of a new file
processFile( @_ ); $spaceBeforeFolder = 1; } } # End of the folder @lineToPrint = ( @tabs, "\}\n" ); for ( @configurations ) { push( @{ $outputs{$_} }, @lineToPrint ); } pop( @tabs ); }
#################################################### sub processConfigOption { my($line) = shift; my($tool) = shift;
# Get the keyname and value if ( $line !~ /(\w+)="([^"\n]*)(.*)/ ) { return; }
my($keyname) = $1; my($keyvalue) = $2; my($lastChar) = $3; my($outputvalue);
# Lookup the keyname if ( $outputvalue = $configOptionsSingleValue{$tool}{$keyname} ) { # A single value option - outputvalue is the VPC defined keyname # Translate TRUE/FALSE to Yes/No $keyvalue =~ s/TRUE/Yes/; $keyvalue =~ s/FALSE/No/;
$keyname = $outputvalue; } elsif ( $outputvalue = $configOptionValues{$keyname}{$keyvalue} ) { # A multi-value option - outputvalue is the desired option setting in string form
my($translatedName) = $configOptionsMultiValue{$keyname};
# Do some bookkeeping for later if ( $translatedName =~ /^SubSystem$/ && $outputvalue =~ /Windows/ ) { $configurationSubsystem = "win"; } elsif ( $translatedName =~ /^ConfigurationType$/ ) { $baseConfiguration = $outputvalue; }
if ( $usestring ) { return $translatedName, $outputvalue; } else { return $translatedName, $keyvalue; } } else { # For debugging print( "Line ", $lineCt, ": Error, no config found for Tool: ", $tool, ", ", $keyname, "=", $keyvalue, "\n" ); # push( @tempOutput, "\/\/" ); }
# special handling for multi-line options if ( !$lastChar ) { my($nextline) = ( @lines[++$lineCt] =~ /([^\n]*)/ ); while( $nextline !~ /\"/ ) { $keyvalue = join( '', $keyvalue, "\" \\ \"\\n\"\n", @tabs, $keytabs{0}, "\"", $nextline ); ($nextline) = ( @lines[++$lineCt] =~ /([^\n]*)/ ); } }
# replace " and ..\ and .\ in option values $keyvalue =~ s/(?<=[^\\])\Q$srcdirBackslash\E\\/\$SRCDIR\\/g; $keyvalue =~ s/(?<=[^\/])\Q$srcdirForwardslash\E\//\$SRCDIR\\/g; $keyvalue =~ s/^\Q$srcdirBackslash\E\\/\$SRCDIR\\/g; $keyvalue =~ s/^\Q$srcdirForwardslash\E\//\$SRCDIR\\/g; $keyvalue =~ s/^\.\\//g; $keyvalue =~ s/\"\;/\$QUOTE/g;
return $keyname, $keyvalue;
}
#################################################### sub processBuildTool { push( @tabs, "\t" ); # Grab the tool name
$_[++$lineCt] =~ ( /Name="([^"]+)"/ ); my($toolName) = $1;
if ( !$toolNames{$toolName} ) { pop( @tabs ); while ( $_[$lineCt] !~ /\/\>$/ ) { ++$lineCt; } return; }
my( @tempOutput );
if ( !$parsingFiles ) { push( @tempOutput, "\n" ); } push( @tempOutput, @tabs, "\$", $toolNames{$toolName}, "\n" ); push( @tempOutput, @tabs, "\{\n" );
# Loop until the /> tag
my($keyname); my($keyvalue); my($optionsFound) = 0; while ( $_[$lineCt] !~ /\/\>$/ ) { ($keyname, $keyvalue) = processConfigOption( $_[++$lineCt], $toolName );
if ( $keyname ) { if ( $keyvalue || !$stripEmptyOptions ) { $optionsFound = 1; } my($len) = $tabstop * int( (length( $keyname ) + $tabstop + 1) / $tabstop ); push( @tempOutput, @tabs, "\t\$", $keyname, $keytabs{$len}, "\"", $keyvalue, "\"\n" ); } }
pop( @tabs ); # End of the tool if ( $optionsFound ) { push( @{ $configOutput{$currentConfig} }, @tempOutput, @tabs, "\t}\n" ); return 1; } return 0; }
#################################################### sub processConfiguration { my( $configOptionsFound ) = 0; my( $startedGeneral ) = 0;
# Loop until the </Configuration> tag
while ( $_[++$lineCt] !~ /^\s*\<\/(File)*Configuration\>$/ ) { if ( $_[$lineCt] =~ /^\s*\<Tool$/ ) { if ( $startedGeneral ) { # close out the faked "General" category $startedGeneral = 0; push( @{ $configOutput{$currentConfig} }, @tabs, "\}\n" ); pop( @tabs ); }
# Start of a new build tool
$configOptionsFound += processBuildTool( @_ ); } elsif ( $_[$lineCt] =~ /=/ ) { # Process the main configuration properties
if ( !$startedGeneral && !$parsingFiles ) { # start the fake "General" category $startedGeneral = 1; push( @tabs, "\t" ); push( @{ $configOutput{$currentConfig} }, @tabs, "\$General\n" ); push( @{ $configOutput{$currentConfig} }, @tabs, "\{\n" ); }
my($keyname); my($keyvalue); ($keyname, $keyvalue) = processConfigOption( $_[$lineCt], "General" );
if ( $keyname ) { # Handle some special cases if ( $keyname =~ /^ExcludedFromBuild$/ && $keyvalue =~ /^Yes$/ ) { @{ $configOutput{$currentConfig} } = (); return 1; }
++$configOptionsFound; my($len) = $tabstop * int( (length( $keyname ) + $tabstop + 1) / $tabstop ); push( @{ $configOutput{$currentConfig} }, @tabs, "\t\$", $keyname, $keytabs{$len}, "\"", $keyvalue, "\"\n" ); } } }
# See if any config options were recorded if ( !$configOptionsFound ) { return -1; }
return 0; }
###################################################### # Code section ######################################################
if ( !$ARGV[0] ) { print( "Error: no project name specified\n" ); exit; }
# Read in the source file
my $infile = $ARGV[0]; $infile =~ s/.vcproj//; open(INFILE, "$infile.vcproj" );
@lines = <INFILE>; close( INFILE );
my(@pathArray) = split(/\\/, $infile ); my($vcprojname) = $pathArray[$#pathArray];
unless ( $outputPath ) { $outputPath = $infile; $outputPath =~ s/$vcprojname//; }
# build the fileheader my(@fileheader); push( @fileheader, "\/\/-----------------------------------------------------------------------------\n" ); push( @fileheader, "\/\/\t",uc($vcprojname),".VPC\n" ); push( @fileheader, "\/\/\n" ); push( @fileheader, "\/\/\tProject Script\n" ); push( @fileheader, "\/\/-----------------------------------------------------------------------------\n" ); push( @fileheader, "\/\/ ***** AUTO-GENERATED: PLEASE FIXUP MANUALLY BEFORE USING THIS SCRIPT! *****\n" ); push( @fileheader, "\n" );
push( @fileheader, "\$Macro SRCDIR\t\t\".." ); $srcdirBackslash = ".."; my($dirct) = $#pathArray - 2; for ( my($i) = 0; $i < $dirct; ++$i ) { push( @fileheader, "\\.." ); $srcdirBackslash = join( "\\", $srcdirBackslash, ".." ); } $srcdirForwardslash = $srcdirBackslash; $srcdirForwardslash =~ s/\\/\//g; push( @fileheader, "\"\n" );
# Process the file one line at a time
my $folderOpenBrace = 0; for( $lineCt = 0; $lineCt < @lines; ++$lineCt ) { my($line) = @lines[$lineCt];
if ( !$nameFound && $line =~ ( /Name="([^"]+)"/ ) ) { $projectName = $1;
# Print the project name my $capName = $projectName; $capName =~ s/\b(\w)/\U$1/g; @lineToPrint = ( "\$Project \"", $capName, "\"\n\{\n" ); for ( @configurations ) { push( @{ $outputs{$_} }, @lineToPrint ); } $nameFound = 1; $folderOpenBrace = 1;
# Clean up the directory
# for ( @configurations ) # { # # delete the existing files # my($filename) = join('_', $vcprojname, $configurationNames{$_} ); # if( $outputPath ) # { # $filename = join('/', $outputPath, $filename ); # $filename =~ s/\//\\/g; # } # system( "del /Q $filename.vpc" ); # } }
if ( $line =~ /^\s*\<Configuration$/ ) { # Start of a new configuration
# Get the configuration name and then process the configuration
my($configLine) = @lines[++$lineCt]; set_current_configuration( $configLine );
$configLine =~ ( /Name="([\w\s]*)\|/ ); my($configName) = ( $1 =~ /(Debug|Release)/ ); $currentConfig = join( '_', $currentConfig, $configName );
push( @{ $configOutput{$currentConfig} }, "\$Configuration\t\"", $configName, "\"\n" ); push( @{ $configOutput{$currentConfig} }, "\{\n" );
processConfiguration( @lines );
# end if this configuration push( @{ $configOutput{$currentConfig} }, "\}\n\n" ); } elsif ( $line =~ /^\s*\<Files\>$/ ) { # end of configurations section - write out the files
# first, finish filling in the header info
my($configtype) = $baseConfigurationTypes{$baseConfiguration}; if ( $configtype =~ /lib/ ) { push( @fileheader, "\$Macro OUTLIBDIR\t\"\$SRCDIR\\lib\\XXXX\"\n" ); } else { push( @fileheader, "\$Macro OUTBINDIR\t\"\$SRCDIR\\..\\game\\bin\"\n" ); } push( @fileheader, "\n" ); push( @fileheader, "\$Include \"\$SRCDIR\\vpc_scripts\\source_" ); push( @fileheader, $configtype ); if ( $configtype =~ /exe/ ) { push( @fileheader, "_", $configurationSubsystem ); } push( @fileheader, "_win32_base.vpc\"\n" ); # push( @fileheader, "_win32_base.vpc\"\t\[\$WIN32\|\|\$LINUX\]\n" ); # push( @fileheader, "\$Include \"\$SRCDIR\\vpc_scripts\\source_" ); # push( @fileheader, $configtype ); # push( @fileheader, "_x360_base.vpc\"\t\t\[\$X360\]\n" ); push( @fileheader, "\n" );
for ( @configurations ) { my $joinedname = join( '_', $_, "Debug" );
# print the configs if ( @{ $configOutput{$joinedname} } > 0 ) { my($filename) = join('_', $vcprojname, $configurationNames{$_} ); if( $outputPath ) { $filename = join('/', $outputPath, $filename ); } open ( OUTFILE, ">$filename.vpc" );
print OUTFILE @fileheader; print OUTFILE @{ $configOutput{$joinedname} };
$joinedname = join( '_', $_, "Release" ); print OUTFILE @{ $configOutput{$joinedname} };
close ( OUTFILE ); } }
$parsingFiles = 1; } elsif ( $line =~ /^\s*\<Filter$/ ) { # Start of a new folder
if ( $spaceBeforeFolder == 1 ) { $spaceBeforeFolder = 0; for ( @configurations ) { push( @{ $outputs{$_} }, "\n" ); } }
processFolder( @lines ); } elsif ( $line =~ /^\s*\<File$/ ) { # Start of a new file
if ( $spaceBeforeFolder == 1 ) { $spaceBeforeFolder = 0; for ( @configurations ) { push( @{ $outputs{$_} }, "\n" ); } }
processFile( @lines ); } }
my $projectCt = 0;
for ( @configurations ) { push( @{ $outputs{$_} }, "\}\n" );
if ( $filesAdded{$_} ) { ++$projectCt;
# print the files my($filename) = join('_', $vcprojname, $configurationNames{$_} ); if( $outputPath ) { $filename = join('/', $outputPath, $filename ); } open ( OUTFILE, ">>$filename.vpc" ); print OUTFILE @{ $outputs{$_} }; close ( OUTFILE ); } }
if ( $projectCt == 1 ) { my $oldname = join('_', $vcprojname, "base.vpc" ); my $newname = join('', $vcprojname, ".vpc" ); if( $outputPath ) { $oldname = join('/', $outputPath, $oldname ); $newname = join('/', $outputPath, $newname ); }
rename $oldname, $newname; }
|