build fix
[mono.git] / mcs / class / Mono.GetOptions / OptionDetails.cs
1 //
2 // OptionDetails.cs
3 //
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
5 //
6 // (C) 2002 Rafael Teixeira
7 //
8
9 using System;
10 using System.Collections;
11 using System.IO;
12 using System.Reflection;
13
14 namespace Mono.GetOptions
15 {
16         public enum WhatToDoNext
17         {
18                 AbandonProgram,
19                 GoAhead
20         }
21         
22         internal enum OptionProcessingResult
23         {
24                 NotThisOption,
25                 OptionAlone,
26                 OptionConsumedParameter
27         }
28
29         internal class OptionDetails : IComparable
30         {
31                 public char ShortForm;
32                 public string LongForm;
33                 public string AlternateForm;
34                 public string ShortDescription;
35                 public bool NeedsParameter;
36                 public int MaxOccurs; // negative means there is no limit
37                 public int Occurs;
38                 public Options OptionBundle;
39                 public MemberInfo MemberInfo;
40                 public ArrayList Values;
41                 public System.Type ParameterType;
42                 public string paramName = null;
43                 public string ParamName 
44                 {
45                         get 
46                         { 
47                                 if (paramName == null)
48                                 {
49                                         int whereBegins = ShortDescription.IndexOf("{");
50                                         if (whereBegins < 0)
51                                                 paramName = "PARAM";
52                                         else
53                                         {
54                                                 int whereEnds = ShortDescription.IndexOf("}");
55                                                 if (whereEnds < whereBegins)
56                                                         whereEnds = ShortDescription.Length+1;
57                                                 
58                                                 paramName = ShortDescription.Substring(whereBegins + 1, whereEnds - whereBegins - 1);
59                                                 ShortDescription = 
60                                                         ShortDescription.Substring(0, whereBegins) + 
61                                                         paramName +
62                                                         ShortDescription.Substring(whereEnds + 1);
63                                         }
64                                 }
65                                 return paramName;
66                         }
67                 }
68                                 
69                 public static bool Verbose = false;
70                 
71                 public override string ToString()
72                 {
73                         string optionHelp;
74                         // TODO: Yet not that good
75                         optionHelp = "  ";
76                         optionHelp += (this.ShortForm != ' ') ? "-"+this.ShortForm+" " : "   ";
77                         optionHelp += (this.LongForm != string.Empty && this.LongForm != null) ? "--"+this.LongForm : "";
78                         if (NeedsParameter)
79                         {
80                                 if (this.LongForm != string.Empty && this.LongForm != null)
81                                         optionHelp += ":"; 
82                                 optionHelp += ParamName; 
83                         }
84                         optionHelp = optionHelp.PadRight(32) + " ";
85                         optionHelp += this.ShortDescription;
86                         if (this.AlternateForm != string.Empty && this.AlternateForm != null)
87                                 optionHelp += " [/"+this.AlternateForm + "]";
88                         return optionHelp; 
89                 }
90
91                 private static System.Type TypeOfMember(MemberInfo memberInfo)
92                 {
93                         if ((memberInfo.MemberType == MemberTypes.Field && memberInfo is FieldInfo))
94                                 return ((FieldInfo)memberInfo).FieldType;
95
96                         if ((memberInfo.MemberType == MemberTypes.Property && memberInfo is PropertyInfo))
97                                 return ((PropertyInfo)memberInfo).PropertyType;
98
99                         if ((memberInfo.MemberType == MemberTypes.Method && memberInfo is MethodInfo))
100                         {
101                                 if (((MethodInfo)memberInfo).ReturnType.FullName != typeof(WhatToDoNext).FullName)
102                                         throw new NotSupportedException("Option method must return '" + typeof(WhatToDoNext).FullName + "'");
103
104                                 ParameterInfo[] parameters = ((MethodInfo)memberInfo).GetParameters();
105                                 if ((parameters == null) || (parameters.Length == 0))
106                                         return null;
107                                 else
108                                         return parameters[0].ParameterType;
109                         }
110
111                         throw new NotSupportedException("'" + memberInfo.MemberType + "' memberType is not supported");
112                 }
113
114                 public OptionDetails(MemberInfo memberInfo, OptionAttribute option, Options optionBundle)
115                 {
116                         this.ShortForm = option.ShortForm;
117                         this.LongForm = (option.LongForm == string.Empty)? memberInfo.Name:option.LongForm;
118                         this.AlternateForm = option.AlternateForm;
119                         this.ShortDescription = option.ShortDescription;
120                         this.Occurs = 0;
121                         this.OptionBundle = optionBundle; 
122                         this.MemberInfo = memberInfo;
123                         this.NeedsParameter = false;
124                         this.Values = null;
125                         this.MaxOccurs = 1;
126                         this.ParameterType = TypeOfMember(memberInfo);
127
128                         if (this.ParameterType != null && this.ParameterType.FullName != "System.Boolean")
129                         {
130                                 if (this.LongForm.IndexOf(':') >= 0)
131                                         throw new InvalidOperationException("Options with an embedded colon (':') in their visible name must be boolean!!! [" + this.MemberInfo.ToString() + " isn't]");
132                                 
133                                 this.NeedsParameter = true;
134
135                                 if (option.MaxOccurs != 1)
136                                 {
137                                         if (this.ParameterType.IsArray)
138                                         {
139                                                 this.Values = new ArrayList();
140                                                 this.MaxOccurs = option.MaxOccurs;
141                                         }
142                                         else
143                                         {
144                                                 if (this.MemberInfo is MethodInfo || this.MemberInfo is PropertyInfo)
145                                                         this.MaxOccurs = option.MaxOccurs;
146                                                 else
147                                                         throw new InvalidOperationException("MaxOccurs set to non default value (" + option.MaxOccurs + ") for a [" + this.MemberInfo.ToString() + "] option");
148                                         }
149                                 }
150                         }
151                 }
152
153                 internal string Key
154                 {
155                         get { return ((this.ShortForm != ' ') ? this.ShortForm + "" : "") + this.LongForm; }
156                 }
157
158                 int IComparable.CompareTo(object other)
159                 {
160                         return Key.CompareTo(((OptionDetails)other).Key);
161                 }
162
163                 public void TransferValues()
164                 {
165                         if (Values != null)
166                         {
167                                 if (MemberInfo is FieldInfo)
168                                 {
169                                         ((FieldInfo)MemberInfo).SetValue(OptionBundle, Values.ToArray(ParameterType.GetElementType()));
170                                         return;
171                                 }
172
173                                 if (MemberInfo is PropertyInfo) 
174                                 {
175                                         ((PropertyInfo)MemberInfo).SetValue(OptionBundle, Values.ToArray(ParameterType.GetElementType()), null);
176                                         return;
177                                 }
178
179                                 if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, new object[] { Values.ToArray(ParameterType.GetElementType()) }) == WhatToDoNext.AbandonProgram)
180                                         System.Environment.Exit(1);
181                         }
182                 }
183
184                 private void Occurred(int howMany)
185                 {
186                         Occurs += howMany;
187
188                         if (MaxOccurs > 0 && Occurs > MaxOccurs)
189                                 throw new IndexOutOfRangeException("Option " + ShortForm + " can be used at most " + MaxOccurs + " times");
190                 }
191
192                 private void DoIt()
193                 {
194                         if (!NeedsParameter)
195                         {
196                                 Occurred(1);
197
198                                 if (Verbose)
199                                         Console.WriteLine("<" + this.LongForm + "> set to [true]");
200
201                                 if (MemberInfo is FieldInfo)
202                                 {
203                                         ((FieldInfo)MemberInfo).SetValue(OptionBundle, true);
204                                         return;
205                                 }
206                                 if (MemberInfo is PropertyInfo)
207                                 {
208                                         ((PropertyInfo)MemberInfo).SetValue(OptionBundle, true, null);
209                                         return;
210                                 }
211                                 if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, null) == WhatToDoNext.AbandonProgram)
212                                         System.Environment.Exit(1);
213
214                                 return;
215                         }
216                 }
217                 
218                 private void DoIt(string parameterValue)
219                 {
220                         if (parameterValue == null)
221                                 parameterValue = "";
222
223                         string[] parameterValues = parameterValue.Split(',');
224
225                         Occurred(parameterValues.Length);
226
227                         foreach (string parameter in parameterValues)
228                         {
229
230                                 object convertedParameter = null;
231
232                                 if (Verbose)
233                                         Console.WriteLine("<" + this.LongForm + "> set to [" + parameter + "]");
234
235                                 if (Values != null && parameter != null)
236                                 {
237                                         convertedParameter = Convert.ChangeType(parameter, ParameterType.GetElementType());
238                                         Values.Add(convertedParameter);
239                                         continue;
240                                 }
241
242                                 if (parameter != null)
243                                         convertedParameter = Convert.ChangeType(parameter, ParameterType);
244
245                                 if (MemberInfo is FieldInfo)
246                                 {
247                                         ((FieldInfo)MemberInfo).SetValue(OptionBundle, convertedParameter);
248                                         continue;
249                                 }
250
251                                 if (MemberInfo is PropertyInfo)
252                                 {
253                                         ((PropertyInfo)MemberInfo).SetValue(OptionBundle, convertedParameter, null);
254                                         continue;
255                                 }
256
257                                 if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, new object[] { convertedParameter }) == WhatToDoNext.AbandonProgram)
258                                         System.Environment.Exit(1);
259                         }
260                 }
261
262                 private bool StartsLikeAnOption(string arg)
263                 {
264                         return (arg != null && arg[0] == '-');
265                 }
266
267                 private bool IsThisOption(string arg)
268                 {
269                         if (StartsLikeAnOption(arg))
270                         {
271                                 arg = arg.TrimStart('-');
272                                 return (arg == "" + ShortForm || arg == LongForm || arg == AlternateForm);
273                         }
274                         return false;
275                 }
276
277                 public OptionProcessingResult ProcessArgument(string arg, string nextArg)
278                 {
279                         if (IsThisOption(arg))
280                         {
281                                 if (!NeedsParameter)
282                                 {
283                                         DoIt();
284                                         return OptionProcessingResult.OptionAlone;
285                                 }
286                                 else
287                                 {
288                                         if (StartsLikeAnOption(nextArg))
289                                         {
290                                                 DoIt(null);
291                                                 return OptionProcessingResult.OptionAlone;
292                                         }
293                                         else
294                                         {
295                                                 DoIt(nextArg);
296                                                 return OptionProcessingResult.OptionConsumedParameter;
297                                         }
298                                 }
299                         }
300
301                         if (IsThisOption(arg + ":" + nextArg))
302                         {
303                                 DoIt();
304                                 return OptionProcessingResult.OptionConsumedParameter;
305                         }
306
307                         return OptionProcessingResult.NotThisOption;
308                 }
309         }
310 }