* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / tools / monop / monop.cs
1 //
2 // monop -- a semi-clone of javap
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      John Luke  (john.luke@gmail.com)
7 //
8 // (C) 2004 Ben Maurer
9 // (C) 2004 John Luke
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33
34 using System;
35 using System.CodeDom.Compiler;
36 using System.Collections;
37 using System.Diagnostics;
38 using System.IO;
39 using System.Reflection;
40 using System.Text;
41
42 class MonoP {
43         static string assembly;
44         
45         // very common namespaces, all in corlib
46         static readonly string [] v_common_ns = {
47                 "System",
48                 "System.Collections",
49                 "System.Reflection",
50                 "System.Text",
51                 "System.IO"
52         };
53         
54         static readonly string [] common_assemblies = {
55                 "System.Xml.dll",
56                 "System.Web.dll",
57                 "gtk-sharp.dll",
58                 "glib-sharp.dll"
59         };
60         
61         static readonly string [] common_ns = {
62                 "System.Xml",
63                 "System.Web",
64                 "Gtk",
65                 "GLib"
66         };
67         
68         static Type GetType (string tname, bool ignoreCase)
69         {
70                 Type t;
71                 if (assembly != null) {
72                         Assembly a = GetAssembly (assembly, true);
73                         t = a.GetType (tname, false, ignoreCase);
74                 } else 
75                         t = Type.GetType (tname, false, ignoreCase);
76
77                 return t;
78         }
79         
80         static string SearchTypes (string name, ref Type retval, out int count)
81         {
82                 StringBuilder sb = new StringBuilder ();
83                 Type current = null;
84                 count = 0;
85
86                 string [] assemblies = GetKnownAssemblyNames ();
87                 for (int i = 0; i < assemblies.Length; i++) {
88                         Assembly a = GetAssembly (assemblies [i], false);
89                         if (a == null)
90                                 continue;
91
92                         Type [] types = a.GetTypes ();
93                         for (int j = 0; j < types.Length; j++) {
94                                 Type t = types [j];
95                                 if (t.IsPublic == false)
96                                         continue;
97                                 
98                                 if (t.Name == name || t.Name.ToLower ().IndexOf (name.ToLower ()) > 0) {
99                                         current = t;
100                                         count ++;
101                                         sb.Append (t.FullName + " from " + a.Location + "\n");
102                                 }
103                         }
104                 }
105
106                 if (count == 0) 
107                         return null;
108
109                 if (count == 1) {
110                         retval = current;
111                         return String.Empty;
112                 }
113                 
114                 return sb.ToString ();
115         }
116
117         static string [] GetKnownAssemblyNames ()
118         {
119                 Process p = new Process ();
120                 p.StartInfo.UseShellExecute = false;
121                 p.StartInfo.RedirectStandardOutput = true;
122                 p.StartInfo.FileName = "gacutil";
123                 p.StartInfo.Arguments = "-l";
124                 try {
125                         p.Start ();
126                 }
127                 catch {
128                         Console.WriteLine ("WARNING: gacutil could not be found.");
129                         return new string[0];
130                 }
131
132                 string s;
133                 ArrayList names = new ArrayList ();
134                 StreamReader output = p.StandardOutput;
135
136                 while ((s = output.ReadLine ()) != null)
137                         names.Add (s);
138
139                 p.WaitForExit ();
140                 
141                 int length = names.Count - 1;
142                 string [] retval = new string [length];
143                 retval [0] = typeof (Object).Assembly.FullName;         
144                 names.CopyTo (1, retval, 1, length - 1); // skip the first and last line
145                 return retval;
146         }
147
148         static Assembly GetAssembly (string assembly, bool exit)
149         {
150                 Assembly a = null;
151
152                 // if -r:~/foo.dll syntax is used the shell misses it
153                 if (assembly.StartsWith ("~/"))
154                         assembly = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), assembly.Substring (2));
155
156                 try {
157                         // if it exists try to use LoadFrom
158                         if (File.Exists (assembly))
159                                 a = Assembly.LoadFrom (assembly);
160                         // if it looks like a fullname try that
161                         else if (assembly.Split (',').Length == 4)
162                                 a = Assembly.Load (assembly);
163                         // see if MONO_PATH has it
164                         else
165                                 a = LoadFromMonoPath (assembly);
166                 } catch {
167                         // ignore exception it gets handled below
168                 }
169
170                 // last try partial name
171                 // this (apparently) is exception safe
172                 if (a == null)
173                         a = Assembly.LoadWithPartialName (assembly);
174
175                 if (a == null && exit) {
176                         Console.WriteLine ("Could not load {0}", MonoP.assembly);
177                         Environment.Exit (1);
178                 }
179
180                 return a;
181         }
182
183         static Assembly LoadFromMonoPath (string assembly)
184         {
185                 // ; on win32, : everywhere else
186                 char sep = (Path.DirectorySeparatorChar == '/' ? ':' : ';');
187                 string[] paths = Environment.GetEnvironmentVariable ("MONO_PATH").Split (sep);
188                 foreach (string path in paths) {        
189                         string apath = Path.Combine (path, assembly);
190                         if (File.Exists (apath))
191                                 return Assembly.LoadFrom (apath);       
192                 }
193                 return null;
194         }
195
196         static Type GetType (string tname)
197         {
198                 return GetType (tname, false);
199         }
200
201         static void PrintRefs (string assembly)
202         {
203                 Assembly a = GetAssembly (assembly, true);
204                 foreach (AssemblyName an in a.GetReferencedAssemblies ())
205                         Console.WriteLine (an);
206         }
207
208         static void PrintTypes (string assembly, bool show_private, bool filter_obsolete)
209         {
210                 Assembly a = GetAssembly (assembly, true);
211
212                 Console.WriteLine ();
213                 Console.WriteLine ("Assembly Information:");
214
215                 object[] cls = a.GetCustomAttributes (typeof (CLSCompliantAttribute), false);
216                 if (cls.Length > 0) {
217                         CLSCompliantAttribute cca = cls[0] as CLSCompliantAttribute;
218                         if (cca.IsCompliant)
219                                 Console.WriteLine ("[CLSCompliant]");
220                 }
221
222                 foreach (string ai in a.ToString ().Split (','))
223                         Console.WriteLine (ai.Trim ());
224                         
225                 Console.WriteLine ();
226                 Type [] types = show_private ? a.GetTypes () : a.GetExportedTypes ();
227                 Array.Sort (types, new TypeSorter ());
228
229                 int obsolete_count = 0;
230                 foreach (Type t in types) {
231                         if (filter_obsolete && t.IsDefined (typeof (ObsoleteAttribute), false))
232                                 obsolete_count ++;
233                         else
234                                 Console.WriteLine (t.FullName);
235                 }
236
237                 Console.WriteLine ("\nTotal: {0} types.", types.Length - obsolete_count);
238         }
239         
240         internal static void Completion (string prefix)
241         {
242                 foreach (Type t in typeof (object).Assembly.GetExportedTypes ()) {
243                         if (t.Name.StartsWith (prefix)) {
244                                 if (Array.IndexOf (v_common_ns, t.Namespace) != -1) {
245                                         Console.WriteLine (t.Name);
246                                         return;
247                                 }
248                         }
249                         
250                         if (t.FullName.StartsWith (prefix)) {
251                                 Console.WriteLine (t.FullName);
252                         }
253                 }
254                 
255                 foreach (string assm in common_assemblies) {
256                         try {
257                                 
258                                 Assembly a = GetAssembly (assm, true);
259                                 foreach (Type t in a.GetExportedTypes ()) {
260                                         
261                                         if (t.Name.StartsWith (prefix)) {
262                                                 if (Array.IndexOf (common_ns, t.Namespace) != -1) {
263                                                         Console.WriteLine (t.Name);
264                                                         return;
265                                                 }
266                                         }
267                                         
268                                         if (t.FullName.StartsWith (prefix)) {
269                                                 Console.WriteLine (t.FullName);
270                                         }
271                                 }
272                                 
273                         } catch {
274                         }
275                 }
276                 
277         }
278
279         static void Main (string [] args)
280         {
281                 Options options = new Options ();
282                 if (!options.ProcessArgs (args))
283                         return;
284                 
285                 if (options.AssemblyReference != null) {
286                         assembly = options.AssemblyReference;
287                         
288                         if (options.Type == null) {
289                                 if (options.PrintRefs)
290                                         PrintRefs (assembly);
291                                 else
292                                         PrintTypes (assembly, options.ShowPrivate, options.FilterObsolete);
293                                 return;
294                         }
295                 }
296
297                 string message = null;
298                 string tname = options.Type;
299                 Type t = null;
300                 int count;
301
302                 if (options.Search) {
303                         string matches = SearchTypes (tname, ref t, out count);
304
305                         if (count == 0)
306                                 goto notfound;
307
308                         if (count == 1)
309                                 goto found;
310                         
311                         if (count > 1){
312                                 Console.WriteLine ("Found " + count + " types that match:");
313                                 Console.WriteLine (matches);
314                                 return;
315                         }
316                 }
317                         
318                 t = GetType (tname);
319
320                 if (t == null) {
321                         // Try some very common ones, dont load anything
322                         foreach (string ns in v_common_ns) {
323                                 t = GetType (ns + "." + tname, true);
324                                 if (t != null)
325                                         goto found;
326                         }
327                 }
328
329                 if (t == null) {
330                         foreach (string assm in GetKnownAssemblyNames ()) {
331                                 try {
332                                         Assembly a = GetAssembly (assm, false);
333                                         t = a.GetType (tname, false, true);
334                                         if (t != null) {
335                                                 message = String.Format ("{0} is included in the {1} assembly.",
336                                                                 t.FullName, 
337                                                                 t.Assembly.GetName ().Name);
338                                                 goto found;
339                                         }
340                                         foreach (string ns in common_ns) {
341                                                 t = a.GetType (ns + "." + tname, false, true);
342                                                 if (t != null) {
343                                                         message = String.Format ("{0} is included in the {1} assembly.",
344                                                                         t.FullName, 
345                                                                         t.Assembly.GetName ().Name);
346                                                         goto found;
347                                                 }
348                                         }
349                                 } catch {
350                                 }
351                         }
352                 }
353
354         notfound:
355                 if (t == null) {
356                         Console.WriteLine ("Could not find {0}", tname);
357                         return;
358                 }
359         found:
360                 //
361                 // This gets us nice buffering
362                 //
363                 StreamWriter sw = new StreamWriter (Console.OpenStandardOutput (), Console.Out.Encoding);                               
364                 new Outline (t, sw, options).OutlineType ();
365                 sw.Flush ();
366
367                 if (message != null)
368                         Console.WriteLine (message);
369         }
370 }
371