OptionDetails.cs
上传用户:huiyue
上传日期:2022-04-08
资源大小:1429k
文件大小:13k
源码类别:

搜索引擎

开发平台:

ASP/ASPX

  1. //
  2. // OptionDetails.cs
  3. //
  4. // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
  5. //
  6. // (C) 2002 Rafael Teixeira
  7. //
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. // 
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. // 
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Collections;
  30. using System.IO;
  31. using System.Reflection;
  32. namespace Mono.GetOptions
  33. {
  34. public enum WhatToDoNext
  35. {
  36. AbandonProgram,
  37. GoAhead
  38. }
  39. internal enum OptionProcessingResult
  40. {
  41. NotThisOption,
  42. OptionAlone,
  43. OptionConsumedParameter
  44. }
  45. internal class OptionDetails : IComparable
  46. {
  47. public string ShortForm;
  48. public string LongForm;
  49. public string AlternateForm;
  50. public string ShortDescription;
  51. public bool NeedsParameter;
  52. public int MaxOccurs; // negative means there is no limit
  53. public int Occurs;
  54. public bool BooleanOption;
  55. public Options OptionBundle;
  56. public MemberInfo MemberInfo;
  57. public ArrayList Values;
  58. public System.Type ParameterType;
  59. public string paramName = null;
  60. public bool VBCStyleBoolean;
  61. public bool SecondLevelHelp;
  62. public bool Hidden;
  63. public OptionDetails NextAlternate  = null;
  64. private string ExtractParamName(string shortDescription)
  65. {
  66. int whereBegins = shortDescription.IndexOf("{");
  67. if (whereBegins < 0)
  68. paramName = "PARAM";
  69. else {
  70. int whereEnds = shortDescription.IndexOf("}");
  71. if (whereEnds < whereBegins)
  72. whereEnds = shortDescription.Length+1;
  73. paramName = shortDescription.Substring(whereBegins + 1, whereEnds - whereBegins - 1);
  74. shortDescription = 
  75. shortDescription.Substring(0, whereBegins) + 
  76. paramName +
  77. shortDescription.Substring(whereEnds + 1);
  78. }
  79. return shortDescription;
  80. }
  81. public string ParamName { get { return paramName; } }
  82. private bool verboseParsing { get { return OptionBundle.VerboseParsingOfOptions || OptionBundle.DebuggingOfOptions; } }
  83. // private bool debugOptions { get { return OptionBundle.DebuggingOfOptions; } }
  84. private OptionsParsingMode parsingMode { get { return OptionBundle.ParsingMode; } } 
  85. private bool useGNUFormat { get { return (parsingMode & OptionsParsingMode.GNU_DoubleDash) == OptionsParsingMode.GNU_DoubleDash; } } 
  86. private bool dontSplitOnCommas { get { return OptionBundle.DontSplitOnCommas; } } 
  87. private string linuxLongPrefix {
  88. get { 
  89. return (useGNUFormat? "--":"-"); 
  90. }
  91. public string DefaultForm
  92. {
  93. get {
  94. string shortPrefix = "-";
  95. string longPrefix = linuxLongPrefix;
  96. if (parsingMode == OptionsParsingMode.Windows) {
  97. shortPrefix = "/";
  98. longPrefix = "/";
  99. }
  100. if (this.ShortForm != string.Empty)
  101. return shortPrefix+this.ShortForm;
  102. else
  103. return longPrefix+this.LongForm;
  104. }
  105. }
  106. private string optionHelp = null;
  107. public override string ToString()
  108. {
  109. if  (optionHelp == null)
  110. {
  111. string shortPrefix;
  112. string longPrefix;
  113. bool hasLongForm = (this.LongForm != null && this.LongForm != string.Empty);
  114. if (this.OptionBundle.ParsingMode == OptionsParsingMode.Windows) {
  115. shortPrefix = "/";
  116. longPrefix = "/";
  117. } else {
  118. shortPrefix = "-";
  119. longPrefix = linuxLongPrefix;
  120. }
  121. optionHelp = "  ";
  122. optionHelp += (this.ShortForm != string.Empty) ? shortPrefix+this.ShortForm+" " : "   ";
  123. optionHelp += hasLongForm ? longPrefix+this.LongForm : "";
  124. if (NeedsParameter) {
  125. if (hasLongForm)
  126. optionHelp += ":"; 
  127. optionHelp += ParamName; 
  128. } else if (BooleanOption && VBCStyleBoolean) {
  129. optionHelp += "[+|-]";
  130. }
  131. optionHelp += "t";
  132. if (this.AlternateForm != string.Empty && this.AlternateForm != null)
  133. optionHelp += "Also "+ shortPrefix + this.AlternateForm + (NeedsParameter?(":"+ParamName):"") +". ";
  134. optionHelp += this.ShortDescription;
  135. }
  136. return optionHelp;
  137. }
  138. private static System.Type TypeOfMember(MemberInfo memberInfo)
  139. {
  140. if ((memberInfo.MemberType == MemberTypes.Field && memberInfo is FieldInfo))
  141. return ((FieldInfo)memberInfo).FieldType;
  142. if ((memberInfo.MemberType == MemberTypes.Property && memberInfo is PropertyInfo))
  143. return ((PropertyInfo)memberInfo).PropertyType;
  144. if ((memberInfo.MemberType == MemberTypes.Method && memberInfo is MethodInfo))
  145. {
  146. if (((MethodInfo)memberInfo).ReturnType.FullName != typeof(WhatToDoNext).FullName)
  147. throw new NotSupportedException("Option method must return '" + typeof(WhatToDoNext).FullName + "'");
  148. ParameterInfo[] parameters = ((MethodInfo)memberInfo).GetParameters();
  149. if ((parameters == null) || (parameters.Length == 0))
  150. return null;
  151. else
  152. return parameters[0].ParameterType;
  153. }
  154. throw new NotSupportedException("'" + memberInfo.MemberType + "' memberType is not supported");
  155. }
  156. public OptionDetails(MemberInfo memberInfo, OptionAttribute option, Options optionBundle)
  157. {
  158. this.ShortForm = ("" + option.ShortForm).Trim();
  159. if (option.LongForm == null)
  160. this.LongForm = string.Empty;
  161. else
  162. this.LongForm = (option.LongForm == string.Empty)? memberInfo.Name:option.LongForm;
  163. this.AlternateForm = option.AlternateForm;
  164. this.ShortDescription = ExtractParamName(option.ShortDescription);
  165. this.Occurs = 0;
  166. this.OptionBundle = optionBundle; 
  167. this.BooleanOption = false;
  168. this.MemberInfo = memberInfo;
  169. this.NeedsParameter = false;
  170. this.Values = null;
  171. this.MaxOccurs = 1;
  172. this.VBCStyleBoolean = option.VBCStyleBoolean;
  173. this.SecondLevelHelp = option.SecondLevelHelp;
  174. this.Hidden = false; // TODO: check other attributes
  175. this.ParameterType = TypeOfMember(memberInfo);
  176. if (this.ParameterType != null)
  177. {
  178. if (this.ParameterType.FullName != "System.Boolean")
  179. {
  180. if (this.LongForm.IndexOf(':') >= 0)
  181. throw new InvalidOperationException("Options with an embedded colon (':') in their visible name must be boolean!!! [" + 
  182. this.MemberInfo.ToString() + " isn't]");
  183. this.NeedsParameter = true;
  184. if (option.MaxOccurs != 1)
  185. {
  186. if (this.ParameterType.IsArray)
  187. {
  188. this.Values = new ArrayList();
  189. this.MaxOccurs = option.MaxOccurs;
  190. }
  191. else
  192. {
  193. if (this.MemberInfo is MethodInfo || this.MemberInfo is PropertyInfo)
  194. this.MaxOccurs = option.MaxOccurs;
  195. else
  196. throw new InvalidOperationException("MaxOccurs set to non default value (" + option.MaxOccurs + ") for a [" + 
  197. this.MemberInfo.ToString() + "] option");
  198. }
  199. }
  200. }
  201. else
  202. {
  203. this.BooleanOption = true;
  204. if (option.MaxOccurs != 1)
  205. {
  206. if (this.MemberInfo is MethodInfo || this.MemberInfo is PropertyInfo)
  207. this.MaxOccurs = option.MaxOccurs;
  208. else
  209. throw new InvalidOperationException("MaxOccurs set to non default value (" + option.MaxOccurs + ") for a [" + 
  210. this.MemberInfo.ToString() + "] option");
  211. }
  212. }
  213. }
  214. }
  215. internal string Key
  216. {
  217. get { 
  218. if (useGNUFormat) {
  219. string ShortID = this.ShortForm.ToUpper();
  220. if (ShortID == string.Empty)
  221. ShortID = "ZZ";
  222. return  ShortID + " " + this.LongForm; 
  223. } else
  224. return this.LongForm + " " + this.ShortForm; 
  225. }
  226. }
  227. int IComparable.CompareTo(object other)
  228. {
  229. return Key.CompareTo(((OptionDetails)other).Key);
  230. }
  231. public void TransferValues()
  232. {
  233. if (Values != null)
  234. {
  235. if (MemberInfo is FieldInfo)
  236. {
  237. ((FieldInfo)MemberInfo).SetValue(OptionBundle, Values.ToArray(ParameterType.GetElementType()));
  238. return;
  239. }
  240. if (MemberInfo is PropertyInfo) 
  241. {
  242. ((PropertyInfo)MemberInfo).SetValue(OptionBundle, Values.ToArray(ParameterType.GetElementType()), null);
  243. return;
  244. }
  245. if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, new object[] { Values.ToArray(ParameterType.GetElementType()) }) == WhatToDoNext.AbandonProgram)
  246. System.Environment.Exit(1);
  247. }
  248. }
  249. private int HowManyBeforeExceedingMaxOccurs(int howMany)
  250. {
  251. if (MaxOccurs > 0 && (Occurs + howMany) > MaxOccurs) {
  252. System.Console.Error.WriteLine("Option " + LongForm + " can be used at most " + MaxOccurs + " times. Ignoring extras...");
  253. howMany = MaxOccurs - Occurs;
  254. }
  255. Occurs += howMany;
  256. return howMany;
  257. }
  258. private bool AddingOneMoreExceedsMaxOccurs { get { return HowManyBeforeExceedingMaxOccurs(1) < 1; } }
  259. private void DoIt(bool setValue)
  260. {
  261. if (AddingOneMoreExceedsMaxOccurs) 
  262. return;
  263. if (verboseParsing)
  264. Console.WriteLine("<{0}> set to [{1}]", this.LongForm, setValue);
  265. if (MemberInfo is FieldInfo)
  266. {
  267. ((FieldInfo)MemberInfo).SetValue(OptionBundle, setValue);
  268. return;
  269. }
  270. if (MemberInfo is PropertyInfo)
  271. {
  272. ((PropertyInfo)MemberInfo).SetValue(OptionBundle, setValue, null);
  273. return;
  274. }
  275. if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, null) == WhatToDoNext.AbandonProgram)
  276. System.Environment.Exit(1);
  277. }
  278. private void DoIt(string parameterValue)
  279. {
  280. if (parameterValue == null)
  281. parameterValue = "";
  282. string[] parameterValues;
  283. if (dontSplitOnCommas || MaxOccurs == 1)
  284. parameterValues = new string[] { parameterValue };
  285. else
  286. parameterValues = parameterValue.Split(',');
  287. int waitingToBeProcessed = HowManyBeforeExceedingMaxOccurs(parameterValues.Length);
  288. foreach (string parameter in parameterValues)
  289. {
  290. if (waitingToBeProcessed-- <= 0)
  291. break;
  292. object convertedParameter = null;
  293. if (verboseParsing)
  294. Console.WriteLine("<" + this.LongForm + "> set to [" + parameter + "]");
  295. if (Values != null && parameter != null) {
  296. try {
  297. convertedParameter = Convert.ChangeType(parameter, ParameterType.GetElementType());
  298. } catch (Exception ex) {
  299. Console.WriteLine(String.Format("The value '{0}' is not convertible to the appropriate type '{1}' for the {2} option", parameter, ParameterType.GetElementType().Name, DefaultForm));
  300. }
  301. Values.Add(convertedParameter);
  302. continue;
  303. }
  304. if (parameter != null) {
  305. try {
  306. convertedParameter = Convert.ChangeType(parameter, ParameterType);
  307. } catch (Exception ex) {
  308. Console.WriteLine(String.Format("The value '{0}' is not convertible to the appropriate type '{1}' for the {2} option", parameter, ParameterType.Name, DefaultForm));
  309. continue;
  310. }
  311. }
  312. if (MemberInfo is FieldInfo) {
  313. ((FieldInfo)MemberInfo).SetValue(OptionBundle, convertedParameter);
  314. continue;
  315. }
  316. if (MemberInfo is PropertyInfo) {
  317. ((PropertyInfo)MemberInfo).SetValue(OptionBundle, convertedParameter, null);
  318. continue;
  319. }
  320. if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, new object[] { convertedParameter }) == WhatToDoNext.AbandonProgram)
  321. System.Environment.Exit(1);
  322. }
  323. }
  324. private bool IsThisOption(string arg)
  325. {
  326. if (arg != null && arg != string.Empty)
  327. {
  328. arg = arg.TrimStart('-', '/');
  329. if (VBCStyleBoolean)
  330. arg = arg.TrimEnd('-', '+');
  331. return (arg == ShortForm || arg == LongForm || arg == AlternateForm);
  332. }
  333. return false;
  334. }
  335. public static void LinkAlternatesInsideList(ArrayList list)
  336. {
  337. Hashtable baseForms = new Hashtable(list.Count);
  338. foreach (OptionDetails option in list) {
  339. if (option.LongForm != null && option.LongForm.Trim().Length > 0) {
  340. string[] parts = option.LongForm.Split(':');
  341. if (parts.Length < 2) {
  342. baseForms.Add(option.LongForm, option);
  343. } else {
  344. OptionDetails baseForm = (OptionDetails)baseForms[parts[0]];
  345. if (baseForm != null) {
  346. // simple linked list
  347. option.NextAlternate = baseForm.NextAlternate;
  348. baseForm.NextAlternate = option;
  349. }
  350. }
  351. }
  352. }
  353. }
  354. private bool IsAlternate(string compoundArg)
  355. {
  356. OptionDetails next = NextAlternate;
  357. while (next != null) {
  358. if (next.IsThisOption(compoundArg))
  359. return true;
  360. next = next.NextAlternate;
  361. }
  362. return false;
  363. }
  364. public OptionProcessingResult ProcessArgument(string arg, string nextArg)
  365. {
  366. if (IsAlternate(arg + ":" + nextArg))
  367. return OptionProcessingResult.NotThisOption;
  368. if (IsThisOption(arg))
  369. {
  370. if (!NeedsParameter)
  371. {
  372. if (VBCStyleBoolean && arg.EndsWith("-"))
  373. DoIt(false);
  374. else
  375. DoIt(true);
  376. return OptionProcessingResult.OptionAlone;
  377. }
  378. else
  379. {
  380. DoIt(nextArg);
  381. return OptionProcessingResult.OptionConsumedParameter;
  382. }
  383. }
  384. if (IsThisOption(arg + ":" + nextArg))
  385. {
  386. DoIt(true);
  387. return OptionProcessingResult.OptionConsumedParameter;
  388. }
  389. return OptionProcessingResult.NotThisOption;
  390. }
  391. }
  392. }