(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / Mono.GetOptions / Mono.GetOptions / OptionList.cs
blobfa240a03657d0f2dd647472fb9d58436fa23a8b4
1 //
2 // OptionList.cs
3 //
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
5 //
6 // (C) 2002 Rafael Teixeira
7 //
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System;
31 using System.Collections;
32 using System.IO;
33 using System.Reflection;
34 using System.Text;
36 namespace Mono.GetOptions
39 /// <summary>
40 /// Option Parsing
41 /// </summary>
42 public class OptionList
45 private Options optionBundle = null;
46 private OptionsParsingMode parsingMode;
47 private bool breakSingleDashManyLettersIntoManyOptions;
48 private bool endOptionProcessingWithDoubleDash;
50 private string appExeName;
51 private string appVersion;
53 private string appTitle = "Add a [assembly: AssemblyTitle(\"Here goes the application name\")] to your assembly";
54 private string appCopyright = "Add a [assembly: AssemblyCopyright(\"(c)200n Here goes the copyright holder name\")] to your assembly";
55 private string appDescription = "Add a [assembly: AssemblyDescription(\"Here goes the short description\")] to your assembly";
56 private string appAboutDetails = "Add a [assembly: Mono.About(\"Here goes the short about details\")] to your assembly";
57 private string appUsageComplement = "Add a [assembly: Mono.UsageComplement(\"Here goes the usage clause complement\")] to your assembly";
58 private string[] appAuthors;
60 private ArrayList list = new ArrayList();
61 private ArrayList arguments = new ArrayList();
62 private ArrayList argumentsTail = new ArrayList();
63 private MethodInfo argumentProcessor = null;
65 internal bool MaybeAnOption(string arg)
67 return ((parsingMode & OptionsParsingMode.Windows) > 0 && arg[0] == '/') ||
68 ((parsingMode & OptionsParsingMode.Linux) > 0 && arg[0] == '-');
71 public string Usage
73 get
75 return "Usage: " + appExeName + " [options] " + appUsageComplement;
79 public string AboutDetails
81 get
83 return appAboutDetails;
87 #region Assembly Attributes
89 Assembly entry;
91 private object[] GetAssemblyAttributes(Type type)
93 return entry.GetCustomAttributes(type, false);
96 private string[] GetAssemblyAttributeStrings(Type type)
98 object[] result = GetAssemblyAttributes(type);
100 if ((result == null) || (result.Length == 0))
101 return new string[0];
103 int i = 0;
104 string[] var = new string[result.Length];
106 foreach(object o in result)
107 var[i++] = o.ToString();
109 return var;
112 private void GetAssemblyAttributeValue(Type type, string propertyName, ref string var)
114 object[] result = GetAssemblyAttributes(type);
116 if ((result != null) && (result.Length > 0))
117 var = (string)type.InvokeMember(propertyName, BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance, null, result[0], new object [] {}); ;
120 private void GetAssemblyAttributeValue(Type type, ref string var)
122 object[] result = GetAssemblyAttributes(type);
124 if ((result != null) && (result.Length > 0))
125 var = result[0].ToString();
128 #endregion
130 #region Constructors
132 private void AddArgumentProcessor(MemberInfo memberInfo)
134 if (argumentProcessor != null)
135 throw new NotSupportedException("More than one argument processor method found");
137 if ((memberInfo.MemberType == MemberTypes.Method && memberInfo is MethodInfo))
139 if (((MethodInfo)memberInfo).ReturnType.FullName != typeof(void).FullName)
140 throw new NotSupportedException("Argument processor method must return 'void'");
142 ParameterInfo[] parameters = ((MethodInfo)memberInfo).GetParameters();
143 if ((parameters == null) || (parameters.Length != 1) || (parameters[0].ParameterType.FullName != typeof(string).FullName))
144 throw new NotSupportedException("Argument processor method must have a string parameter");
146 argumentProcessor = (MethodInfo)memberInfo;
148 else
149 throw new NotSupportedException("Argument processor marked member isn't a method");
152 private void Initialize(Options optionBundle)
154 if (optionBundle == null)
155 throw new ArgumentNullException("optionBundle");
157 entry = Assembly.GetEntryAssembly();
158 appExeName = entry.GetName().Name;
159 appVersion = entry.GetName().Version.ToString();
161 this.optionBundle = optionBundle;
162 this.parsingMode = optionBundle.ParsingMode ;
163 this.breakSingleDashManyLettersIntoManyOptions = optionBundle.BreakSingleDashManyLettersIntoManyOptions;
164 this.endOptionProcessingWithDoubleDash = optionBundle.EndOptionProcessingWithDoubleDash;
166 GetAssemblyAttributeValue(typeof(AssemblyTitleAttribute), "Title", ref appTitle);
167 GetAssemblyAttributeValue(typeof(AssemblyCopyrightAttribute), "Copyright", ref appCopyright);
168 GetAssemblyAttributeValue(typeof(AssemblyDescriptionAttribute), "Description", ref appDescription);
169 GetAssemblyAttributeValue(typeof(Mono.AboutAttribute), ref appAboutDetails);
170 GetAssemblyAttributeValue(typeof(Mono.UsageComplementAttribute), ref appUsageComplement);
171 appAuthors = GetAssemblyAttributeStrings(typeof(AuthorAttribute));
172 if (appAuthors.Length == 0)
174 appAuthors = new String[1];
175 appAuthors[0] = "Add one or more [assembly: Mono.GetOptions.Author(\"Here goes the author name\")] to your assembly";
178 foreach(MemberInfo mi in optionBundle.GetType().GetMembers())
180 object[] attribs = mi.GetCustomAttributes(typeof(OptionAttribute), true);
181 if (attribs != null && attribs.Length > 0)
182 list.Add(new OptionDetails(mi, (OptionAttribute)attribs[0], optionBundle));
183 else
185 attribs = mi.GetCustomAttributes(typeof(ArgumentProcessorAttribute), true);
186 if (attribs != null && attribs.Length > 0)
187 AddArgumentProcessor(mi);
192 public OptionList(Options optionBundle)
194 Initialize(optionBundle);
197 #endregion
199 #region Prebuilt Options
201 private void ShowTitleLines()
203 Console.WriteLine(appTitle + " " + appVersion + " - " + appCopyright);
204 Console.WriteLine(appDescription);
205 Console.WriteLine();
208 private void ShowAbout()
210 ShowTitleLines();
211 Console.WriteLine(appAboutDetails);
212 StringBuilder sb = new StringBuilder("Authors: ");
213 bool first = true;
214 foreach(string s in appAuthors)
216 if (first)
217 first = false;
218 else
219 sb.Append(", ");
220 sb.Append(s);
222 Console.WriteLine(sb.ToString());
225 private void ShowHelp()
227 ShowTitleLines();
228 Console.WriteLine(Usage);
229 Console.WriteLine("Options:");
230 foreach (OptionDetails option in list)
231 Console.WriteLine(option);
234 private void ShowUsage()
236 Console.WriteLine(Usage);
237 Console.Write("Short Options: ");
238 foreach (OptionDetails option in list)
239 Console.Write(option.ShortForm.Trim());
240 Console.WriteLine();
244 private void ShowUsage(string errorMessage)
246 Console.WriteLine("ERROR: " + errorMessage.TrimEnd());
247 ShowUsage();
250 internal WhatToDoNext DoUsage()
252 ShowUsage();
253 return WhatToDoNext.AbandonProgram;
256 internal WhatToDoNext DoAbout()
258 ShowAbout();
259 return WhatToDoNext.AbandonProgram;
262 internal WhatToDoNext DoHelp()
264 ShowHelp();
265 return WhatToDoNext.AbandonProgram;
268 #endregion
270 #region Arguments Processing
272 public string[] ExpandResponseFiles(string[] args)
274 ArrayList result = new ArrayList();
276 foreach(string arg in args)
278 if (arg.StartsWith("@"))
280 try
282 StreamReader tr = new StreamReader(arg.Substring(1));
283 string line;
284 while ((line = tr.ReadLine()) != null)
286 result.AddRange(line.Split());
288 tr.Close();
290 catch (FileNotFoundException exception)
292 Console.WriteLine("Could not find response file: " + arg.Substring(1));
293 continue;
295 catch (Exception exception)
297 Console.WriteLine("Error trying to read response file: " + arg.Substring(1));
298 Console.WriteLine(exception.Message);
299 continue;
302 else
303 result.Add(arg);
306 return (string[])result.ToArray(typeof(string));
309 public string[] NormalizeArgs(string[] args)
311 bool ParsingOptions = true;
312 ArrayList result = new ArrayList();
314 foreach(string arg in ExpandResponseFiles(args))
316 if (arg.Length > 0)
318 if (ParsingOptions)
320 if (endOptionProcessingWithDoubleDash && (arg == "--"))
322 ParsingOptions = false;
323 continue;
326 if ((parsingMode & OptionsParsingMode.Linux) > 0 &&
327 arg[0] == '-' && arg[1] != '-' &&
328 breakSingleDashManyLettersIntoManyOptions)
330 foreach(char c in arg.Substring(1)) // many single-letter options
331 result.Add("-" + c); // expand into individualized options
332 continue;
335 if (MaybeAnOption(arg))
337 int pos = arg.IndexOfAny(":=".ToCharArray());
339 if(pos < 0)
340 result.Add(arg);
341 else {
342 result.Add(arg.Substring(0, pos));
343 result.Add(arg.Substring(pos+1));
345 continue;
348 else
350 argumentsTail.Add(arg);
351 continue;
354 // if nothing else matches then it get here
355 result.Add(arg);
359 return (string[])result.ToArray(typeof(string));
362 public string[] ProcessArgs(string[] args)
364 string arg;
365 string nextArg;
366 bool OptionWasProcessed;
368 list.Sort();
370 args = NormalizeArgs(args);
374 int argc = args.Length;
375 for (int i = 0; i < argc; i++)
377 arg = args[i];
378 if (i+1 < argc)
379 nextArg = args[i+1];
380 else
381 nextArg = null;
383 OptionWasProcessed = false;
385 if (arg.StartsWith("-") || arg.StartsWith("/"))
387 foreach(OptionDetails option in list)
389 OptionProcessingResult result = option.ProcessArgument(arg, nextArg);
390 if (result != OptionProcessingResult.NotThisOption)
392 OptionWasProcessed = true;
393 if (result == OptionProcessingResult.OptionConsumedParameter)
394 i++;
395 break;
400 if (!OptionWasProcessed)
402 if (OptionDetails.Verbose)
403 Console.WriteLine("argument [" + arg + "]");
405 arguments.Add(arg);
409 foreach(OptionDetails option in list)
410 option.TransferValues();
412 foreach(string argument in argumentsTail)
413 arguments.Add(argument);
415 if (argumentProcessor == null)
416 return (string[])arguments.ToArray(typeof(string));
418 foreach(string argument in arguments)
419 argumentProcessor.Invoke(optionBundle, new object[] { argument });
421 catch (Exception ex)
423 System.Console.WriteLine(ex.ToString());
424 System.Environment.Exit(1);
427 return null;
430 #endregion