From 1485dd1675abeafff4b860f5f4bca0c67ff7eab9 Mon Sep 17 00:00:00 2001 From: Herve-M Date: Sun, 20 Sep 2015 19:22:21 +0200 Subject: [PATCH] Add basic arguments validation --- OpenRA.Game/IUtilityCommand.cs | 2 + .../UtilityCommands/CheckCodeStyle.cs | 10 ++-- .../UtilityCommands/CheckSequenceSprites.cs | 10 ++-- .../UtilityCommands/CheckYaml.cs | 6 +- .../UtilityCommands/ConvertPngToShpCommand.cs | 6 +- .../ConvertSpriteToPngCommand.cs | 8 ++- .../UtilityCommands/CreateManPage.cs | 5 ++ .../UtilityCommands/Extensions.cs | 1 - .../UtilityCommands/ExtractFilesCommand.cs | 7 ++- .../ExtractLanguageStringsCommand.cs | 6 +- .../UtilityCommands/ExtractLuaDocsCommand.cs | 5 ++ .../ExtractTraitDocsCommand.cs | 5 ++ .../UtilityCommands/FixClassicTilesets.cs | 8 ++- .../UtilityCommands/GenerateMinimapCommand.cs | 8 ++- .../UtilityCommands/GetMapHashCommand.cs | 8 ++- .../UtilityCommands/ImportLegacyMapCommand.cs | 5 ++ .../UtilityCommands/LegacyMapImporter.cs | 2 - .../UtilityCommands/RemapShpCommand.cs | 7 ++- .../UtilityCommands/ReplayMetadataCommand.cs | 5 ++ .../UtilityCommands/UpgradeMapCommand.cs | 10 ++-- .../UtilityCommands/UpgradeModCommand.cs | 7 ++- .../UtilityCommands/ImportD2kMapCommand.cs | 5 ++ .../UtilityCommands/LegacyTilesetImporter.cs | 5 ++ OpenRA.Utility/Program.cs | 58 ++++++++++++++----- 24 files changed, 146 insertions(+), 53 deletions(-) diff --git a/OpenRA.Game/IUtilityCommand.cs b/OpenRA.Game/IUtilityCommand.cs index d7054b20c1..54ec65c8e7 100644 --- a/OpenRA.Game/IUtilityCommand.cs +++ b/OpenRA.Game/IUtilityCommand.cs @@ -17,6 +17,8 @@ namespace OpenRA /// string Name { get; } + bool ValidateArguments(string[] args); + void Run(ModData modData, string[] args); } } diff --git a/OpenRA.Mods.Common/UtilityCommands/CheckCodeStyle.cs b/OpenRA.Mods.Common/UtilityCommands/CheckCodeStyle.cs index de5614d18b..3fc54bf4ad 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CheckCodeStyle.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CheckCodeStyle.cs @@ -9,12 +9,7 @@ #endregion using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; -using OpenRA.FileSystem; -using OpenRA.Traits; using StyleCop; namespace OpenRA.Mods.Common.UtilityCommands @@ -24,6 +19,11 @@ namespace OpenRA.Mods.Common.UtilityCommands public string Name { get { return "--check-code-style"; } } int violationCount; + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("DIRECTORY", "Check the *.cs source code files in a directory for code style violations.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs b/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs index 75140a4378..2d4d1593c9 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs @@ -9,14 +9,9 @@ #endregion using System; -using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; using OpenRA.FileSystem; using OpenRA.Graphics; -using OpenRA.Traits; -using StyleCop; namespace OpenRA.Mods.Common.UtilityCommands { @@ -24,6 +19,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--check-sequence-sprites"; } } + public bool ValidateArguments(string[] args) + { + return true; + } + [Desc("Check the sequence definitions for missing sprite files.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs b/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs index 0e3cadc59e..57aa5497a5 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.FileSystem; using OpenRA.Traits; namespace OpenRA.Mods.Common.UtilityCommands @@ -34,6 +33,11 @@ namespace OpenRA.Mods.Common.UtilityCommands Console.WriteLine("OpenRA.Utility(1,1): Warning: {0}", e); } + public bool ValidateArguments(string[] args) + { + return true; + } + [Desc("[MAPFILE]", "Check a mod or map for certain yaml errors.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ConvertPngToShpCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ConvertPngToShpCommand.cs index ae16024173..123bd613ec 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ConvertPngToShpCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ConvertPngToShpCommand.cs @@ -15,7 +15,6 @@ using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Text; using OpenRA.FileFormats; using OpenRA.Mods.Common.SpriteLoaders; @@ -25,6 +24,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--shp"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("PNGFILE [PNGFILE ...]", "Combine a list of PNG images into a SHP")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs index dacc502ca1..6129af076e 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs @@ -9,14 +9,11 @@ #endregion using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using OpenRA.FileFormats; using OpenRA.Graphics; namespace OpenRA.Mods.Common.UtilityCommands @@ -25,6 +22,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--png"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 3; + } + [Desc("SPRITEFILE PALETTE [--noshadow] [--nopadding]", "Convert a shp/tmp/R8 to a series of PNGs, optionally removing shadow")] public void Run(ModData modData, string[] args) diff --git a/OpenRA.Mods.Common/UtilityCommands/CreateManPage.cs b/OpenRA.Mods.Common/UtilityCommands/CreateManPage.cs index 6f8a6090b2..e9344f1264 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CreateManPage.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CreateManPage.cs @@ -17,6 +17,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--man-page"; } } + public bool ValidateArguments(string[] args) + { + return true; + } + [Desc("Create a man page in troff format.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/Extensions.cs b/OpenRA.Mods.Common/UtilityCommands/Extensions.cs index 5bb4a71507..e7d8e8e607 100644 --- a/OpenRA.Mods.Common/UtilityCommands/Extensions.cs +++ b/OpenRA.Mods.Common/UtilityCommands/Extensions.cs @@ -8,7 +8,6 @@ */ #endregion -using System; using System.Data; using System.Text; diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractFilesCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractFilesCommand.cs index 45c80c1720..cffb2b02e8 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractFilesCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractFilesCommand.cs @@ -9,10 +9,8 @@ #endregion using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using OpenRA.FileSystem; namespace OpenRA.Mods.Common.UtilityCommands @@ -21,6 +19,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--extract"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("Extract files from mod packages to the current directory")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs index 551bc0a0c8..72752da821 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; namespace OpenRA.Mods.Common.UtilityCommands { @@ -20,6 +19,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--extract-language-strings"; } } + public bool ValidateArguments(string[] args) + { + return true; + } + [Desc("Extract translatable strings that are not yet localized and update chrome layout.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs index e95baff556..35d5b57979 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs @@ -21,6 +21,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--lua-docs"; } } + public bool ValidateArguments(string[] args) + { + return true; + } + [Desc("Generate Lua API documentation in MarkDown format.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs index d9378b572f..8b6fbb570c 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs @@ -20,6 +20,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--docs"; } } + public bool ValidateArguments(string[] args) + { + return true; + } + [Desc("Generate trait documentation in MarkDown format.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/FixClassicTilesets.cs b/OpenRA.Mods.Common/UtilityCommands/FixClassicTilesets.cs index 904e8157f2..e5357839c0 100644 --- a/OpenRA.Mods.Common/UtilityCommands/FixClassicTilesets.cs +++ b/OpenRA.Mods.Common/UtilityCommands/FixClassicTilesets.cs @@ -9,15 +9,12 @@ #endregion using System; -using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using OpenRA.FileSystem; using OpenRA.Graphics; -using OpenRA.Traits; -using StyleCop; namespace OpenRA.Mods.Common.UtilityCommands { @@ -25,6 +22,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--fix-classic-tilesets"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("EXTENSIONS", "Fixes missing template tile definitions and adds filename extensions.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/GenerateMinimapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/GenerateMinimapCommand.cs index 4ced98a4b8..344b329bd2 100644 --- a/OpenRA.Mods.Common/UtilityCommands/GenerateMinimapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/GenerateMinimapCommand.cs @@ -9,10 +9,7 @@ #endregion using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using OpenRA.FileSystem; using OpenRA.Graphics; @@ -22,6 +19,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--map-preview"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("MAPFILE", "Render PNG minimap of specified oramap file.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs b/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs index 4d8c7e4141..1a7c212e5f 100644 --- a/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs @@ -9,9 +9,6 @@ #endregion using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace OpenRA.Mods.Common.UtilityCommands { @@ -19,6 +16,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--map-hash"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("MAPFILE", "Generate hash of specified oramap file.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs index 31529006c5..e2dcac0c24 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs @@ -17,6 +17,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--map-import"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("FILENAME", "Convert a legacy INI/MPR map to the OpenRA format.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs b/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs index 49663e96ee..375c2975d2 100644 --- a/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs +++ b/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs @@ -10,8 +10,6 @@ using System; using System.Collections.Generic; -using System.Drawing; -using System.Globalization; using System.IO; using System.Linq; using System.Text; diff --git a/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs b/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs index 8bacd27b6b..e4fb9f6b2a 100644 --- a/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs @@ -13,8 +13,6 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; -using System.Text; -using OpenRA.FileFormats; using OpenRA.FileSystem; using OpenRA.Graphics; using OpenRA.Mods.Common.SpriteLoaders; @@ -26,6 +24,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--remap"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 5; + } + [Desc("SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP", "Remap SHPs to another palette")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/ReplayMetadataCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ReplayMetadataCommand.cs index eaebfcf142..0b556bd295 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ReplayMetadataCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ReplayMetadataCommand.cs @@ -18,6 +18,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--replay-metadata"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("REPLAYFILE", "Print the game metadata from a replay file.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs index 1e08285800..1be5311942 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs @@ -8,17 +8,17 @@ */ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace OpenRA.Mods.Common.UtilityCommands { class UpgradeMapCommand : IUtilityCommand { public string Name { get { return "--upgrade-map"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 3; + } + [Desc("MAP", "CURRENTENGINE", "Upgrade map rules to the latest engine version.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs index 1ca906728b..ee16de91c2 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs @@ -9,10 +9,8 @@ #endregion using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; namespace OpenRA.Mods.Common.UtilityCommands { @@ -20,6 +18,11 @@ namespace OpenRA.Mods.Common.UtilityCommands { public string Name { get { return "--upgrade-mod"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 2; + } + [Desc("CURRENTENGINE", "Upgrade mod rules to the latest engine version.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs b/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs index 840be72081..5b6e596151 100644 --- a/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs +++ b/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs @@ -17,6 +17,11 @@ namespace OpenRA.Mods.D2k.UtilityCommands { public string Name { get { return "--import-d2k-map"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 3; + } + [Desc("FILENAME", "TILESET", "Convert a legacy Dune 2000 MAP file to the OpenRA format.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Mods.TS/UtilityCommands/LegacyTilesetImporter.cs b/OpenRA.Mods.TS/UtilityCommands/LegacyTilesetImporter.cs index 78d7d9b52c..7c540ac0c7 100644 --- a/OpenRA.Mods.TS/UtilityCommands/LegacyTilesetImporter.cs +++ b/OpenRA.Mods.TS/UtilityCommands/LegacyTilesetImporter.cs @@ -20,6 +20,11 @@ namespace OpenRA.Mods.TS.UtilityCommands { public string Name { get { return "--tileset-import"; } } + public bool ValidateArguments(string[] args) + { + return args.Length >= 3; + } + [Desc("FILENAME", "TEMPLATEEXTENSION", "Convert a legacy tileset to the OpenRA format.")] public void Run(ModData modData, string[] args) { diff --git a/OpenRA.Utility/Program.cs b/OpenRA.Utility/Program.cs index b7724ce244..3913994844 100644 --- a/OpenRA.Utility/Program.cs +++ b/OpenRA.Utility/Program.cs @@ -40,17 +40,37 @@ namespace OpenRA.Utility Game.InitializeSettings(Arguments.Empty); var modData = new ModData(modName); args = args.Skip(1).ToArray(); - var actions = new Dictionary>(); + var actions = new Dictionary, Func>>(); foreach (var commandType in modData.ObjectCreator.GetTypesImplementing()) { var command = (IUtilityCommand)Activator.CreateInstance(commandType); - actions.Add(command.Name, command.Run); + var kvp = new KeyValuePair, Func>(command.Run, command.ValidateArguments); + actions.Add(command.Name, kvp); + } + + if (args.Length == 0) + { + PrintUsage(actions); + return; } try { - var action = Exts.WithDefault((a, b) => PrintUsage(actions), () => actions[args[0]]); - action(modData, args); + if (!actions.ContainsKey(args[0])) + throw new ArgumentException(); + + var action = actions[args[0]].Key; + var validateActionArgs = actions[args[0]].Value; + + if (validateActionArgs.Invoke(args)) + { + action.Invoke(modData, args); + } + else + { + Console.WriteLine("Invalid arguments for '{0}'", args[0]); + GetActionUsage(args[0], action); + } } catch (Exception e) { @@ -58,12 +78,17 @@ namespace OpenRA.Utility Log.Write("utility", "Received args: {0}", args.JoinWith(" ")); Log.Write("utility", "{0}", e); - Console.WriteLine("Error: Utility application crashed. See utility.log for details"); - throw; + if (e is ArgumentException) + Console.WriteLine("No such command '{0}'", args[0]); + else + { + Console.WriteLine("Error: Utility application crashed. See utility.log for details"); + throw; + } } } - static void PrintUsage(IDictionary> actions) + static void PrintUsage(IDictionary, Func>> actions) { Console.WriteLine("Run `OpenRA.Utility.exe [MOD]` to see a list of available commands."); Console.WriteLine("The available mods are: " + string.Join(", ", ModMetadata.AllMods.Keys)); @@ -76,17 +101,22 @@ namespace OpenRA.Utility foreach (var key in keys) { - var descParts = actions[key].Method.GetCustomAttributes(true) + GetActionUsage(key, actions[key].Key); + } + } + + static void GetActionUsage(string key, Action action) + { + var descParts = action.Method.GetCustomAttributes(true) .SelectMany(d => d.Lines).ToArray(); - if (descParts.Length == 0) - continue; + if (descParts.Length == 0) + return; - var args = descParts.Take(descParts.Length - 1).JoinWith(" "); - var desc = descParts[descParts.Length - 1]; + var args = descParts.Take(descParts.Length - 1).JoinWith(" "); + var desc = descParts[descParts.Length - 1]; - Console.WriteLine(" {0} {1}{3} {2}{3}", key, args, desc, Environment.NewLine); - } + Console.WriteLine(" {0} {1}{3} {2}{3}", key, args, desc, Environment.NewLine); } } }