2004-12-03 Atsushi Enomoto <atsushi@ximian.com>
[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 using System;
14 using System.CodeDom.Compiler;
15 using System.Collections;
16 using System.Diagnostics;
17 using System.IO;
18 using System.Reflection;
19
20 class MonoP {
21         static string assembly;
22         static BindingFlags default_flags = 
23                 BindingFlags.Instance |
24                 BindingFlags.Static |
25                 BindingFlags.Public;
26         
27         // very common namespaces, all in corlib
28         static readonly string [] v_common_ns = {
29                 "System",
30                 "System.Collections",
31                 "System.Reflection",
32                 "System.Text",
33                 "System.IO"
34         };
35         
36         static readonly string [] common_assemblies = {
37                 "System.Xml.dll",
38                 "System.Web.dll",
39                 "gtk-sharp.dll",
40                 "glib-sharp.dll"
41         };
42         
43         static readonly string [] common_ns = {
44                 "System.Xml",
45                 "System.Web",
46                 "Gtk",
47                 "GLib"
48         };
49         
50         static Type GetType (string tname, bool ignoreCase)
51         {
52                 Type t;
53                 if (assembly != null) {
54                         Assembly a = GetAssembly (assembly, true);
55                         t = a.GetType (tname, false, ignoreCase);
56                 } else {
57                         t = Type.GetType (tname, false, ignoreCase);
58                 }
59
60                 return t;
61         }       
62
63         static string [] GetAssemblyNamesFromGAC ()
64         {
65                 Process p = new Process ();
66                 p.StartInfo.UseShellExecute = false;
67                 p.StartInfo.RedirectStandardOutput = true;
68                 p.StartInfo.FileName = "gacutil";
69                 p.StartInfo.Arguments = "-l";
70                 p.Start ();
71
72                 string s;
73                 ArrayList names = new ArrayList ();
74                 StreamReader output = p.StandardOutput;
75
76                 while ((s = output.ReadLine ()) != null)
77                         names.Add (s);
78
79                 p.WaitForExit ();
80
81                 string [] retval = new string [names.Count - 2];
82                 names.CopyTo (1, retval, 0, retval.Length); // skip the first and last line
83                 return retval;
84         }
85
86         static Assembly GetAssembly (string assembly, bool exit)
87         {
88                 Assembly a = null;
89
90                 try {
91                         // if it exists try to use LoadFrom
92                         if (File.Exists (assembly))
93                                 a = Assembly.LoadFrom (assembly);
94                         // if it looks like a fullname try that
95                         else if (assembly.Split (',').Length == 4)
96                                 a = Assembly.Load (assembly);
97                         // see if MONO_PATH has it
98                         else
99                                 a = LoadFromMonoPath (assembly);
100                 } catch {
101                         // ignore exception it gets handled below
102                 }
103
104                 // last try partial name
105                 // this (apparently) is exception safe
106                 if (a == null)
107                         a = Assembly.LoadWithPartialName (assembly);
108
109                 if (a == null && exit) {
110                         Console.WriteLine ("Could not load {0}", MonoP.assembly);
111                         Environment.Exit (1);
112                 }
113
114                 return a;
115         }
116
117         static Assembly LoadFromMonoPath (string assembly)
118         {
119                 // ; on win32, : everywhere else
120                 char sep = (Path.DirectorySeparatorChar == '/' ? ':' : ';');
121                 string[] paths = Environment.GetEnvironmentVariable ("MONO_PATH").Split (sep);
122                 foreach (string path in paths)
123                 {       
124                         string apath = Path.Combine (path, assembly);
125                         if (File.Exists (apath))
126                                 return Assembly.LoadFrom (apath);       
127                 }
128                 return null;
129         }
130
131         static Type GetType (string tname)
132         {
133                 return GetType (tname, false);
134         }
135         
136         static void PrintTypes (string assembly)
137         {
138                 Assembly a = GetAssembly (assembly, true);
139
140                 Console.WriteLine ();
141                 Console.WriteLine ("Assembly Information:");
142
143                 object[] cls = a.GetCustomAttributes (typeof (CLSCompliantAttribute), false);
144                 if (cls.Length > 0)
145                 {
146                         CLSCompliantAttribute cca = cls[0] as CLSCompliantAttribute;
147                         if (cca.IsCompliant)
148                                 Console.WriteLine ("[CLSCompliant]");
149                 }
150
151                 foreach (string ai in a.ToString ().Split (','))
152                         Console.WriteLine (ai.Trim ());
153                         
154                 Console.WriteLine ();
155                 Type [] types = a.GetExportedTypes ();
156
157                 foreach (Type t in types)
158                         Console.WriteLine (t.FullName);
159
160                 Console.WriteLine ("\nTotal: {0} types.", types.Length);
161         }
162         
163         static void Completion (string prefix)
164         {
165                 foreach (Type t in typeof (object).Assembly.GetExportedTypes ()) {
166                         if (t.Name.StartsWith (prefix)) {
167                                 if (Array.IndexOf (v_common_ns, t.Namespace) != -1) {
168                                         Console.WriteLine (t.Name);
169                                         return;
170                                 }
171                         }
172                         
173                         if (t.FullName.StartsWith (prefix)) {
174                                 Console.WriteLine (t.FullName);
175                         }
176                 }
177                 
178                 foreach (string assm in common_assemblies) {
179                         try {
180                                 
181                                 Assembly a = GetAssembly (assm, true);
182                                 foreach (Type t in a.GetExportedTypes ()) {
183                                         
184                                         if (t.Name.StartsWith (prefix)) {
185                                                 if (Array.IndexOf (common_ns, t.Namespace) != -1) {
186                                                         Console.WriteLine (t.Name);
187                                                         return;
188                                                 }
189                                         }
190                                         
191                                         if (t.FullName.StartsWith (prefix)) {
192                                                 Console.WriteLine (t.FullName);
193                                         }
194                                 }
195                                 
196                         } catch {
197                         }
198                 }
199                 
200         }
201
202         static void PrintUsage ()
203         {
204                 Console.WriteLine ("Usage is: monop [option] [-c] [-r:Assembly] [class-name]");
205         }
206
207         static void PrintHelp ()
208         {
209                 PrintUsage ();
210                 Console.WriteLine ("");
211                 Console.WriteLine ("options:");
212                 Console.WriteLine ("\t--declared-only,-d\tOnly show members declared in the Type");
213                 Console.WriteLine ("\t--help,-h\t\tShow this information");
214                 Console.WriteLine ("\t--private,-p\t\tShow private members");
215         }
216         
217         static void Main (string [] args)
218         {
219                 if (args.Length < 1) {
220                         PrintUsage ();
221                         return;
222                 }
223
224                 if (args.Length == 1 && (args[0] == "--help" || args[0] == "-h"))
225                 {
226                         PrintHelp ();
227                         return;
228
229                 }
230                 
231                 int i = 0;
232                 if (args [0].StartsWith ("-r:") || args [0].StartsWith ("/r:")){
233                         i++;
234                         assembly = args [0].Substring (3);
235                         
236                         if (args.Length == 1) {
237                                 PrintTypes (assembly);
238                                 return;
239                         }
240                 }
241                 
242                 if (args [0] == "-c") {
243                         Completion (args [1]);
244                         return;
245                 }
246
247                 if (args [i] == "--private" || args [i] == "-p") {
248                                 default_flags |= BindingFlags.NonPublic;
249                                 i++;
250                 }
251
252                 if (args [i] == "--declared-only" || args [i] == "-d") {
253                                 default_flags |= BindingFlags.DeclaredOnly;
254                                 i++;
255                 }
256
257                 if (args.Length < i + 1) {
258                         PrintUsage ();
259                         return;
260                 }
261
262                 string message = null;
263                 string tname = args [i];
264                 Type t = GetType (tname);
265
266                 if (t == null) {
267                         // Try some very common ones, dont load anything
268                         foreach (string ns in v_common_ns) {
269                                 t = GetType (ns + "." + tname, true);
270                                 if (t != null)
271                                         goto found;
272                         }
273                 }
274
275                 if (t == null) {
276                         foreach (string assm in GetAssemblyNamesFromGAC ()) {
277                                 try {
278                                         Assembly a = GetAssembly (assm, false);
279                                         t = a.GetType (tname, false, true);
280                                         if (t != null) {
281                                                 message = String.Format ("{0} is included in the {1} assembly.",
282                                                                 t.FullName, 
283                                                                 t.Assembly.GetName ().Name);
284                                                 goto found;
285                                         }
286                                         foreach (string ns in common_ns) {
287                                                 t = a.GetType (ns + "." + tname, false, true);
288                                                 if (t != null) {
289                                                         message = String.Format ("{0} is included in the {1} assembly.",
290                                                                 t.FullName, 
291                                                                 t.Assembly.GetName ().Name);
292                                                         goto found;
293                                                 }
294                                         }
295                                 } catch {
296                                 }
297                         }
298                 }
299                 
300                 if (t == null) {
301                         Console.WriteLine ("Could not find {0}", tname);
302                         return;
303                 }
304         found:
305                 //
306                 // This gets us nice buffering
307                 //
308                 StreamWriter sw = new StreamWriter (Console.OpenStandardOutput (), Console.Out.Encoding);
309                 new Outline (t, sw).OutlineType (default_flags);
310                 sw.Flush ();
311
312                 if (message != null)
313                         Console.WriteLine (message);
314         }
315 }
316