25 using System.Collections;
26 using System.Collections.Generic;
27 using System.ComponentModel;
28 using System.Diagnostics;
30 using System.Reflection;
31 using System.Runtime.InteropServices;
53 private const int STD_OUTPUT_HANDLE = -11;
54 private static int hConsoleHandle;
55 private static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
56 private static int OriginalColors;
57 private Dictionary<string, FieldInfo> optionalOptions =
new Dictionary<string, FieldInfo>();
58 private List<string> optionalUsageHelp =
new List<string>();
59 private object optionsObject;
60 private string[] optionNames;
62 private Queue<FieldInfo> requiredOptions =
new Queue<FieldInfo>();
64 private List<string> requiredUsageHelp =
new List<string>();
68 ConsoleInfo =
new CONSOLE_SCREEN_BUFFER_INFO();
69 hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
70 GetConsoleScreenBufferInfo(hConsoleHandle, ref ConsoleInfo);
71 OriginalColors = ConsoleInfo.wAttributes;
79 private ConsoleProgram(
object optionsObjectArg,
int padOptions = 16)
81 this.optionsObject = optionsObjectArg ??
this;
84 foreach (FieldInfo field
in optionsObject.GetType().GetFields())
86 var option = GetOptionName(field);
88 var optionName = option.Name;
93 requiredOptions.Enqueue(field);
95 requiredUsageHelp.Add(string.Format(
"{0}", option.Name));
100 optionalOptions.Add(optionName, field);
102 if (field.FieldType == typeof (
bool))
104 optionalUsageHelp.Add(string.Format(
"/{0,-" + padOptions +
"}{1}", optionName, option.Description ?? string.Empty));
108 optionalUsageHelp.Add(string.Format(
"/{0,-" + padOptions +
"}{1}", string.Format(
"{0}{1}", optionName, option.Value ??
"<value>"), option.Description ??
string.Empty));
113 optionNames =
new string[optionalOptions.Count];
114 optionalOptions.Keys.CopyTo(optionNames, 0);
115 Array.Sort(optionNames, (left, right) => -
string.Compare(left, right, StringComparison.Ordinal));
117 if (optionalOptions.Count > 0)
119 requiredUsageHelp.Insert(0,
"<options>");
125 Console.WriteLine(
"{0} - {1}", GetAssemblyTitle(), Assembly.GetEntryAssembly().GetName().Version);
126 Console.WriteLine(
"{0}", GetAssemblyCopyright());
135 return cmdParser.ParseCommandLine(args);
141 foreach (
string arg
in args)
143 if (!ParseArgument(arg.Trim()))
150 FieldInfo missingRequiredOption = null;
152 foreach (var field
in requiredOptions)
154 if (!IsList(field) || GetList(field).Count == 0)
156 missingRequiredOption = field;
161 if (missingRequiredOption != null)
163 ShowError(
"Missing argument '{0}'", GetOptionName(missingRequiredOption).Name);
170 private bool ParseArgument(
string arg)
172 if (arg.StartsWith(
"/") || arg.StartsWith(
"-"))
174 string name = arg.Substring(1);
178 FieldInfo field = null;
182 foreach (var registerName
in optionNames)
184 if (name.StartsWith(registerName, StringComparison.InvariantCultureIgnoreCase))
186 field = optionalOptions[registerName];
187 value = name.Substring(registerName.Length);
194 ShowError(
"Unknown option '{0}'", name);
198 if (
string.IsNullOrEmpty(value))
203 return SetOption(field, value);
208 if (requiredOptions.Count == 0)
210 ShowError(
"Too many arguments");
214 FieldInfo field = requiredOptions.Peek();
218 requiredOptions.Dequeue();
221 return SetOption(field, arg);
225 private bool SetOption(FieldInfo field,
string value)
232 GetList(field).Add(ChangeType(value, ListElementType(field)));
237 field.SetValue(optionsObject, ChangeType(value, field.FieldType));
244 ShowError(
"Invalid value '{0}' for option '{1}'", value, GetOptionName(field).Name);
250 private static object ChangeType(
string value, Type type)
254 return converter.ConvertFromInvariantString(value);
258 private static bool IsList(FieldInfo field)
260 return typeof (IList).IsAssignableFrom(field.FieldType);
264 private IList GetList(FieldInfo field)
266 return (IList) field.GetValue(optionsObject);
270 private static Type ListElementType(FieldInfo field)
272 foreach (var fieldInterface
in field.FieldType.GetInterfaces())
274 if (fieldInterface.IsGenericType && fieldInterface.GetGenericTypeDefinition() == typeof (
IEnumerable<>))
276 return fieldInterface.GetGenericArguments()[0];
283 private static OptionAttribute GetOptionName(FieldInfo field)
285 return GetAttribute<OptionAttribute>(field) ??
new OptionAttribute(field.Name);
293 public void ShowError(
string message, params
object[] args)
295 string name = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName);
298 System.Console.Error.WriteLine(message, args);
300 System.Console.Error.WriteLine();
301 System.Console.Out.WriteLine(
"Usage: {0} {1}", name, string.Join(
" ", requiredUsageHelp.ToArray()));
303 if (optionalUsageHelp.Count > 0)
305 System.Console.Out.WriteLine();
306 System.Console.Out.WriteLine(
"Options:");
308 foreach (
string optional
in optionalUsageHelp)
310 System.Console.Out.WriteLine(
" {0}", optional);
314 System.Console.Out.WriteLine(GetUsageFooter());
317 private static T GetAttribute<T>(ICustomAttributeProvider provider) where T : Attribute
319 var attributes = provider.GetCustomAttributes(typeof (T),
false);
320 if (attributes.Length > 0)
322 return (T)attributes[0];
331 private static string GetAssemblyTitle()
333 var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute),
false);
334 if (attributes.Length > 0)
336 var titleAttribute = (AssemblyTitleAttribute)attributes[0];
337 if (!
string.IsNullOrEmpty(titleAttribute.Title))
338 return titleAttribute.Title;
340 return Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
347 private static string GetAssemblyCopyright()
349 var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute),
false);
350 if (attributes.Length > 0)
352 var titleAttribute = (AssemblyCopyrightAttribute)attributes[0];
353 if (!
string.IsNullOrEmpty(titleAttribute.Copyright))
354 return titleAttribute.Copyright;
361 [DllImport(
"kernel32.dll", EntryPoint =
"GetStdHandle", SetLastError =
true,
362 CharSet = CharSet.Auto,
363 CallingConvention = CallingConvention.StdCall)]
364 private static extern int GetStdHandle(
int nStdHandle);
366 [DllImport(
"kernel32.dll", EntryPoint =
"GetConsoleScreenBufferInfo",
367 SetLastError =
true, CharSet = CharSet.Auto,
368 CallingConvention = CallingConvention.StdCall)]
369 private static extern int GetConsoleScreenBufferInfo(
int hConsoleOutput,
370 ref CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
372 [DllImport(
"kernel32.dll", EntryPoint =
"SetConsoleTextAttribute",
373 SetLastError =
true, CharSet = CharSet.Auto,
374 CallingConvention = CallingConvention.StdCall)]
375 private static extern int SetConsoleTextAttribute(
int hConsoleOutput,
385 SetConsoleTextAttribute(hConsoleHandle, (
int) color);
390 SetConsoleTextAttribute(hConsoleHandle, OriginalColors);
393 #region Nested type: CONSOLE_SCREEN_BUFFER_INFO
395 [StructLayout(LayoutKind.Sequential)]
396 private struct CONSOLE_SCREEN_BUFFER_INFO
399 public COORD dwCursorPosition;
400 public int wAttributes;
401 public SMALL_RECT srWindow;
402 public COORD dwMaximumWindowSize;
407 #region Nested type: COORD
409 [StructLayout(LayoutKind.Sequential)]
418 #region Nested type: OptionAttribute
420 [AttributeUsage(AttributeTargets.Field)]
428 public string Name {
get;
private set; }
430 public string Description {
get; set; }
432 public string Value {
get; set; }
434 public bool Required {
get; set; }
439 #region Nested type: SMALL_RECT
441 [StructLayout(LayoutKind.Sequential)]
442 private struct SMALL_RECT
447 private short Bottom;
477 Intensity = 0x00000008,
524 White = Intensity | Red | Green | Blue,
Intensity background color modifier.
void ShowError(string message, params object[] args)
static bool ParseCommandLine(object options, string[] args, int padOptions=16)
Flags
Enumeration of the new Assimp's flags.
ConsoleProgram(int padOptions=16)
static void PrintHeader()
OptionAttribute(string name)
static void Color(ConsoleColor color)
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
SiliconStudio.Core.Mathematics.Color Color
virtual string GetUsageFooter()
ConsoleColor
Colors used by ConsoleProgram.Color
bool ParseCommandLine(string[] args)
Reusable, reflection based helper for parsing commandline options. Greetings to Shawn Hargreaves...