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