PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/NekoKun.Core/Helpers/CommandLineParser.cs

https://bitbucket.org/nekokun/nekokun
C# | 248 lines | 224 code | 24 blank | 0 comment | 41 complexity | cc38041878deb3bd173112970677d7fa MD5 | raw file
Possible License(s): MIT, CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace NekoKun.Core
  5. {
  6. public class CommandLineParser
  7. {
  8. protected System.Type cmdClass;
  9. protected Dictionary<string, System.Reflection.MethodInfo> methods;
  10. protected List<System.Reflection.MethodInfo> defaults;
  11. public CommandLineParser(System.Type CommandClass)
  12. {
  13. cmdClass = CommandClass;
  14. defaults = new List<System.Reflection.MethodInfo>();
  15. methods = new Dictionary<string,System.Reflection.MethodInfo>();
  16. foreach (var item in cmdClass.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy))
  17. {
  18. object[] attr = item.GetCustomAttributes(typeof(CommandLineEntry), true);
  19. if (attr.Length == 1 && attr[0] is CommandLineEntry)
  20. {
  21. CommandLineEntry entry = attr[0] as CommandLineEntry;
  22. if (entry.IsDefault)
  23. {
  24. defaults.Add(item);
  25. }
  26. methods.Add(item.Name, item);
  27. }
  28. }
  29. methods.Add("?", this.GetType().GetMethod("ShowHelpEntry"));
  30. methods.Add("Help", this.GetType().GetMethod("ShowHelpEntry"));
  31. }
  32. public void ShowHelpEntry(string[] argf)
  33. {
  34. StringBuilder str = new StringBuilder();
  35. str.AppendLine(String.Format("{0} [/command] [(/|-)key[=value]] [files]", System.Reflection.Assembly.GetEntryAssembly().CodeBase));
  36. str.AppendLine();
  37. string[] keysa = new string[this.methods.Count];
  38. this.methods.Keys.CopyTo(keysa, 0);
  39. List<string> keys = new List<string>(keysa);
  40. keys.Sort(StringComparer.OrdinalIgnoreCase);
  41. str.AppendLine("Available commands: ");
  42. foreach (var item in keys)
  43. {
  44. str.AppendLine(item);
  45. str.AppendLine("\t" + this.methods[item].ToString());
  46. str.AppendLine();
  47. }
  48. NekoKun.Core.Application.ShowError(str.ToString());
  49. }
  50. public void ParseAndExecute(string[] args)
  51. {
  52. List<ParsedArgument> arg;
  53. try
  54. {
  55. arg = Parse(args);
  56. }
  57. catch (Exception e)
  58. {
  59. NekoKun.Core.Application.ShowError(e.Message);
  60. return;
  61. }
  62. Execute(arg);
  63. }
  64. public void Execute(List<ParsedArgument> args)
  65. {
  66. if (args == null || args.Count == 0)
  67. {
  68. ExecuteInner(this.defaults.ToArray(), new ParsedArgument[] { }, new string[] { });
  69. return;
  70. }
  71. string entry = null;
  72. if (((args[0].Key!= null && args[0].Key.Length > 0) && (args[0].Value == null || args[0].Value.Length == 0)))
  73. {
  74. entry = args[0].Key;
  75. args.RemoveAt(0);
  76. }
  77. List<string> argfb = new List<string>();
  78. List<ParsedArgument> argvb = new List<ParsedArgument>();
  79. foreach (var item in args)
  80. {
  81. if (item.Key != null && item.Key.Length > 0)
  82. {
  83. argvb.Add(item);
  84. }
  85. else
  86. {
  87. argfb.Add(item.Value);
  88. }
  89. }
  90. string[] argf = argfb.ToArray();
  91. ParsedArgument[] argv = argvb.ToArray();
  92. if (entry != null)
  93. {
  94. List<System.Reflection.MethodInfo> methods = new List<System.Reflection.MethodInfo>();
  95. foreach (var item in this.methods)
  96. {
  97. if (item.Key.Equals(entry, StringComparison.CurrentCultureIgnoreCase) )
  98. {
  99. methods.Add(item.Value);
  100. }
  101. }
  102. if (methods.Count > 0)
  103. ExecuteInner(methods.ToArray(), argv, argf);
  104. else
  105. throw new CommandLineException("Cannot found entry for " + entry, this.cmdClass, entry, null);
  106. }
  107. else
  108. {
  109. ExecuteInner(this.defaults.ToArray(), argv, argf);
  110. }
  111. }
  112. internal void ExecuteInner(System.Reflection.MethodInfo[] methods, ParsedArgument[] param, string[] argf)
  113. {
  114. if (param.Length == 0)
  115. {
  116. foreach (var item in methods)
  117. {
  118. System.Reflection.ParameterInfo[] info = item.GetParameters();
  119. if (info.Length == 1)
  120. {
  121. if (info[0].ParameterType == typeof(string[]))
  122. {
  123. if (item.IsStatic)
  124. item.Invoke(null, new object[] { argf });
  125. else
  126. item.Invoke(this, new object[] { argf });
  127. return;
  128. }
  129. }
  130. }
  131. }
  132. throw new NotImplementedException();
  133. }
  134. public List<ParsedArgument> Parse(string[] args)
  135. {
  136. List<ParsedArgument> arg = new List<ParsedArgument>();
  137. if (args.Length == 0)
  138. return arg;
  139. bool parse = true;
  140. for (int i = 0; i < args.Length; i++)
  141. {
  142. if (parse)
  143. {
  144. if (args[i] == "-")
  145. {
  146. parse = false;
  147. }
  148. else if (args[i].StartsWith("-") || args[i].StartsWith("/"))
  149. {
  150. ParsedArgument item = new ParsedArgument();
  151. int pos = args[i].IndexOf('=');
  152. if (pos >= 0)
  153. {
  154. item.Key = args[i].Substring(1, pos - 1);
  155. item.Value = args[i].Substring(pos + 1);
  156. }
  157. else
  158. {
  159. item.Key = args[i].Substring(1);
  160. }
  161. if (item.Key != null)
  162. arg.Add(item);
  163. else
  164. throw new CommandLineException(
  165. String.Format("Invalid argument: {0}", args[i]),
  166. this.cmdClass, null, args
  167. );
  168. }
  169. else
  170. {
  171. parse = false;
  172. }
  173. }
  174. if (!parse)
  175. {
  176. ParsedArgument item = new ParsedArgument();
  177. item.Value = args[i];
  178. arg.Add(item);
  179. }
  180. }
  181. return arg;
  182. }
  183. public class ParsedArgument
  184. {
  185. public string Key;
  186. public string Value;
  187. }
  188. }
  189. public class CommandLineEntry : System.Attribute {
  190. bool isDefault;
  191. public CommandLineEntry()
  192. : this(false)
  193. {
  194. }
  195. public CommandLineEntry(bool isDefault)
  196. {
  197. this.isDefault = isDefault;
  198. }
  199. public bool IsDefault
  200. {
  201. get { return this.isDefault; }
  202. }
  203. }
  204. public class CommandLineException : System.Exception
  205. {
  206. public System.Type CommandClass;
  207. public string Entry;
  208. public string[] CommandLine;
  209. public CommandLineException(string Message, System.Type CommandClass, string Entry, string[] CommandLine)
  210. : base(Message)
  211. {
  212. this.CommandClass = CommandClass;
  213. this.Entry = Entry;
  214. this.CommandLine = CommandLine;
  215. }
  216. public CommandLineException(string Message, System.Type CommandClass, string Entry, string[] CommandLine, Exception InnerException)
  217. : base(Message, InnerException)
  218. {
  219. this.CommandClass = CommandClass;
  220. this.Entry = Entry;
  221. this.CommandLine = CommandLine;
  222. }
  223. }
  224. }