* Stdlib.cs: Cache delegates passed to Stdlib.signal() so that they survive
[mono.git] / mcs / class / Mono.Posix / Mono.Unix / make-map.cs
1 //
2 // MakeMap.cs: Builds a C map of constants defined on C# land
3 //
4 // Authors:
5 //  Miguel de Icaza (miguel@novell.com)
6 //  Jonathan Pryor (jonpryor@vt.edu)
7 //
8 // (C) 2003 Novell, Inc.
9 // (C) 2004 Jonathan Pryor
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 using System;
33 using System.Collections;
34 using System.IO;
35 using System.Reflection;
36 using System.Runtime.InteropServices;
37
38 delegate void CreateFileHandler (string assembly_name, string file_prefix);
39 delegate void AssemblyAttributesHandler (Assembly assembly);
40 delegate void TypeHandler (Type t, string ns, string fn);
41 delegate void CloseFileHandler (string file_prefix);
42
43 class MakeMap {
44
45         public static int Main (string [] args)
46         {
47                 FileGenerator[] generators = new FileGenerator[]{
48                         new HeaderFileGenerator (),
49                         new SourceFileGenerator (),
50                         new ConvertFileGenerator (),
51                         new MphPrototypeFileGenerator (),
52                 };
53
54                 MakeMap composite = new MakeMap ();
55                 foreach (FileGenerator g in generators) {
56                         composite.FileCreators += new CreateFileHandler (g.CreateFile);
57                         composite.AssemblyAttributesHandler += 
58                                 new AssemblyAttributesHandler (g.WriteAssemblyAttributes);
59                         composite.TypeHandler += new TypeHandler (g.WriteType);
60                         composite.FileClosers += new CloseFileHandler (g.CloseFile);
61                 }
62
63                 return composite.Run (args);
64         }
65
66         event CreateFileHandler FileCreators;
67         event AssemblyAttributesHandler AssemblyAttributesHandler;
68         event TypeHandler TypeHandler;
69         event CloseFileHandler FileClosers;
70
71         int Run (string[] args)
72         {
73                 if (args.Length != 2){
74                         Console.WriteLine ("Usage is: make-map assembly output");
75                         return 1;
76                 }
77                 
78                 string assembly_name = args[0];
79                 string output = args[1];
80
81                 FileCreators (assembly_name, output);
82
83                 Assembly assembly = Assembly.LoadFrom (assembly_name);
84                 AssemblyAttributesHandler (assembly);
85                 
86                 Type [] exported_types = assembly.GetTypes ();
87                         
88                 foreach (Type t in exported_types) {
89                         string ns = t.Namespace;
90                         if (ns == null || !ns.StartsWith ("Mono"))
91                                 continue;
92                         string fn = GetNativeName (t.FullName);
93                         ns = GetNativeName (ns);
94
95                         TypeHandler (t, ns, fn);
96                 }
97                 FileClosers (output);
98
99                 return 0;
100         }
101
102         internal static string GetNativeName (string fn)
103         {
104                 return fn.Replace (".", "_").Replace ("Mono_Unix", "Mono_Posix");
105         }
106 }
107
108 abstract class FileGenerator {
109         public abstract void CreateFile (string assembly_name, string file_prefix);
110
111         public virtual void WriteAssemblyAttributes (Assembly assembly)
112         {
113         }
114
115         public abstract void WriteType (Type t, string ns, string fn);
116         public abstract void CloseFile (string file_prefix);
117
118         protected static void WriteHeader (StreamWriter s, string assembly)
119         {
120                 s.WriteLine (
121                         "/*\n" +
122                         " * This file was automatically generated by make-map from {0}.\n" +
123                         " *\n" +
124                         " * DO NOT MODIFY.\n" +
125                         " */\n" +
126                         "#include <config.h>\n",
127                         assembly);
128         }
129
130         protected static bool CanMapType (Type t, out bool bits)
131         {
132                 object [] attributes = t.GetCustomAttributes (false);
133                 bool map = false;
134                 bits = false;
135                 
136                 foreach (object attr in attributes) {
137                         if (attr.GetType ().Name == "MapAttribute")
138                                 map = true;
139                         if (attr.GetType ().Name == "FlagsAttribute")
140                                 bits = true;
141                 }
142                 return map;
143         }
144
145         protected static string GetNativeType (Type t)
146         {
147                 string ut = t.Name;
148                 if (t.IsEnum)
149                         ut = Enum.GetUnderlyingType (t).Name;
150                 Type et = t.GetElementType ();
151                 if (et != null && et.IsEnum)
152                         ut = Enum.GetUnderlyingType (et).Name;
153
154                 string type = null;
155
156                 switch (ut) {
157                         case "Boolean":       type = "int";             break;
158                         case "Byte":          type = "unsigned char";   break;
159                         case "SByte":         type = "signed char";     break;
160                         case "Int16":         type = "short";           break;
161                         case "UInt16":        type = "unsigned short";  break;
162                         case "Int32":         type = "int";             break;
163                         case "UInt32":        type = "unsigned int";    break;
164                         case "UInt32[]":      type = "unsigned int*";   break;
165                         case "Int64":         type = "gint64";          break;
166                         case "UInt64":        type = "guint64";         break;
167                         case "IntPtr":        type = "void*";           break;
168                         case "Byte[]":        type = "void*";           break;
169                         case "String":        type = "const char*";     break;
170                         case "StringBuilder": type = "char*";           break;
171                         case "Void":          type = "void";            break;
172                         case "HandleRef":     type = "void*";           break;
173                 }
174                 if (type != null)
175                         return string.Format ("{0}{1}", type,
176                                         t.IsByRef ? "*" : "");
177                 return GetTypeName (t);
178         }
179
180         private static string GetTypeName (Type t)
181         {
182                 if (t.Namespace.StartsWith ("System"))
183                         return "int /* warning: unknown mapping for type: " + t.Name + " */";
184                 string ts = "struct " +
185                         MakeMap.GetNativeName (t.FullName).Replace ("+", "_").Replace ("&", "*");
186                 return ts;
187         }
188 }
189
190 class HeaderFileGenerator : FileGenerator {
191         StreamWriter sh;
192
193         public override void CreateFile (string assembly_name, string file_prefix)
194         {
195                 sh = File.CreateText (file_prefix + ".h");
196                 WriteHeader (sh, assembly_name);
197                 sh.WriteLine ("#ifndef INC_Mono_Posix_" + file_prefix + "_H");
198                 sh.WriteLine ("#define INC_Mono_Posix_" + file_prefix + "_H\n");
199                 sh.WriteLine ("#include <glib/gtypes.h>\n");
200                 sh.WriteLine ("G_BEGIN_DECLS\n");
201         }
202
203         public override void WriteType (Type t, string ns, string fn)
204         {
205                 bool bits;
206                 if (!CanMapType (t, out bits))
207                         return;
208                 string etype = GetNativeType (t);
209
210                 WriteLiteralValues (sh, t, fn);
211                 sh.WriteLine ("int {1}_From{2} ({0} x, {0} *r);", etype, ns, t.Name);
212                 sh.WriteLine ("int {1}_To{2} ({0} x, {0} *r);", etype, ns, t.Name);
213                 sh.WriteLine ();
214         }
215
216         static void WriteLiteralValues (StreamWriter sh, Type t, string n)
217         {
218                 object inst = Activator.CreateInstance (t);
219                 foreach (FieldInfo fi in t.GetFields ()){
220                         if (!fi.IsLiteral)
221                                 continue;
222                         sh.WriteLine ("#define {0}_{1} 0x{2:x}", n, fi.Name, fi.GetValue (inst));
223                 }
224         }
225
226         public override void CloseFile (string file_prefix)
227         {
228                 sh.WriteLine ("G_END_DECLS\n");
229                 sh.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_H */\n");
230                 sh.Close ();
231         }
232 }
233
234 class SourceFileGenerator : FileGenerator {
235         StreamWriter sc;
236
237         public override void CreateFile (string assembly_name, string file_prefix)
238         {
239                 sc = File.CreateText (file_prefix + ".c");
240                 WriteHeader (sc, assembly_name);
241
242                 if (file_prefix.IndexOf ("/") != -1)
243                         file_prefix = file_prefix.Substring (file_prefix.IndexOf ("/") + 1);
244                 sc.WriteLine ("#include \"{0}.h\"", file_prefix);
245                 sc.WriteLine ();
246         }
247
248         public override void WriteAssemblyAttributes (Assembly assembly)
249         {
250                 object [] x = assembly.GetCustomAttributes (false);
251                 Console.WriteLine ("Got: " + x.Length);
252                 foreach (object aattr in assembly.GetCustomAttributes (false)) {
253                         Console.WriteLine ("Got: " + aattr.GetType ().Name);
254                         if (aattr.GetType ().Name == "IncludeAttribute"){
255                                 WriteDefines (sc, aattr);
256                                 WriteIncludes (sc, aattr);
257                         }
258                 }
259         }
260
261         static void WriteDefines (TextWriter writer, object o)
262         {
263                 PropertyInfo prop = o.GetType ().GetProperty ("Defines");
264                 if (prop == null)
265                         throw new Exception ("Cannot find 'Defines' property");
266
267                 MethodInfo method = prop.GetGetMethod ();
268                 string [] defines = (string []) method.Invoke (o, null);
269                 foreach (string def in defines) {
270                         writer.WriteLine ("#ifndef {0}", def);
271                         writer.WriteLine ("#define {0}", def);
272                         writer.WriteLine ("#endif /* ndef {0} */", def);
273                 }
274         }
275
276         static void WriteIncludes (TextWriter writer, object o)
277         {
278                 PropertyInfo prop = o.GetType ().GetProperty ("Includes");
279                 if (prop == null)
280                         throw new Exception ("Cannot find 'Includes' property");
281
282                 MethodInfo method = prop.GetGetMethod ();
283                 string [] includes = (string []) method.Invoke (o, null);
284                 foreach (string inc in includes){
285                         if (inc.Length > 3 && 
286                                         string.CompareOrdinal (inc, 0, "ah:", 0, 3) == 0) {
287                                 string i = inc.Substring (3);
288                                 writer.WriteLine ("#ifdef HAVE_" + (i.ToUpper ().Replace ("/", "_").Replace (".", "_")));
289                                 writer.WriteLine ("#include <{0}>", i);
290                                 writer.WriteLine ("#endif");
291                         } else 
292                                 writer.WriteLine ("#include <{0}>", inc);
293                 }
294                 writer.WriteLine ();
295         }
296
297         public override void WriteType (Type t, string ns, string fn)
298         {
299                 bool bits;
300                 if (!CanMapType (t, out bits))
301                         return;
302                 string etype = GetNativeType (t);
303
304                 WriteFromManagedType (t, ns, fn, etype, bits);
305                 WriteToManagedType (t, ns, fn, etype, bits);
306         }
307
308         private void WriteFromManagedType (Type t, string ns, string fn, string etype, bool bits)
309         {
310                 sc.WriteLine ("int {1}_From{2} ({0} x, {0} *r)", etype, ns, t.Name);
311                 sc.WriteLine ("{");
312                 sc.WriteLine ("\t*r = 0;");
313                 // For many values, 0 is a valid value, but doesn't have it's own symbol.
314                 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
315                 // Make 0 valid for all conversions.
316                 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
317                 foreach (FieldInfo fi in t.GetFields ()) {
318                         if (!fi.IsLiteral)
319                                 continue;
320                         if (Attribute.GetCustomAttribute (fi, 
321                                 typeof(ObsoleteAttribute), false) != null) {
322                                 sc.WriteLine ("\t/* {0}_{1} is obsolete; ignoring */", fn, fi.Name);
323                                 continue;
324                         }
325                         if (bits)
326                                 // properly handle case where [Flags] enumeration has helper
327                                 // synonyms.  e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
328                                 sc.WriteLine ("\tif ((x & {0}_{1}) == {0}_{1})", fn, fi.Name);
329                         else
330                                 sc.WriteLine ("\tif (x == {0}_{1})", fn, fi.Name);
331                         sc.WriteLine ("#ifdef {0}", fi.Name);
332                         if (bits)
333                                 sc.WriteLine ("\t\t*r |= {1};", fn, fi.Name);
334                         else
335                                 sc.WriteLine ("\t\t{{*r = {1}; return 0;}}", fn, fi.Name);
336                         sc.WriteLine ("#else /* def {0} */\n\t\t{{errno = EINVAL; return -1;}}", fi.Name);
337                         sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
338                 }
339                 if (bits)
340                         sc.WriteLine ("\treturn 0;");
341                 else
342                         sc.WriteLine ("\terrno = EINVAL; return -1;"); // return error if not matched
343                 sc.WriteLine ("}\n");
344         }
345
346         private void WriteToManagedType (Type t, string ns, string fn, string etype, bool bits)
347         {
348                 sc.WriteLine ("int {1}_To{2} ({0} x, {0} *r)", etype, ns, t.Name);
349                 sc.WriteLine ("{");
350                 sc.WriteLine ("\t*r = 0;", etype);
351                 // For many values, 0 is a valid value, but doesn't have it's own symbol.
352                 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
353                 // Make 0 valid for all conversions.
354                 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
355                 foreach (FieldInfo fi in t.GetFields ()) {
356                         if (!fi.IsLiteral)
357                                 continue;
358                         sc.WriteLine ("#ifdef {0}", fi.Name);
359                         if (bits)
360                                 // properly handle case where [Flags] enumeration has helper
361                                 // synonyms.  e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
362                                 sc.WriteLine ("\tif ((x & {1}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name);
363                         else
364                                 sc.WriteLine ("\tif (x == {1})\n\t\t{{*r = {0}_{1}; return 0;}}", fn, fi.Name);
365                         sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
366                 }
367                 if (bits)
368                         sc.WriteLine ("\treturn 0;");
369                 else
370                         sc.WriteLine ("\terrno = EINVAL; return -1;");
371                 sc.WriteLine ("}\n");
372         }
373
374         public override void CloseFile (string file_prefix)
375         {
376                 sc.Close ();
377         }
378 }
379
380 class ConvertFileGenerator : FileGenerator {
381         StreamWriter scs;
382
383         public override void CreateFile (string assembly_name, string file_prefix)
384         {
385                 scs = File.CreateText (file_prefix + ".cs");
386                 WriteHeader (scs, assembly_name);
387                 scs.WriteLine ("using System;");
388                 scs.WriteLine ("using System.Runtime.InteropServices;");
389                 scs.WriteLine ("using Mono.Unix;\n");
390                 scs.WriteLine ("namespace Mono.Unix {\n");
391                 scs.WriteLine ("\tpublic sealed /* static */ class UnixConvert");
392                 scs.WriteLine ("\t{");
393                 scs.WriteLine ("\t\tprivate UnixConvert () {}\n");
394                 scs.WriteLine ("\t\tprivate const string LIB = \"MonoPosixHelper\";\n");
395                 scs.WriteLine ("\t\tprivate static void ThrowArgumentException (object value)");
396                 scs.WriteLine ("\t\t{");
397                 scs.WriteLine ("\t\t\tthrow new ArgumentOutOfRangeException (\"value\", value,");
398                 scs.WriteLine ("\t\t\t\tLocale.GetText (\"Current platform doesn't support this value.\"));");
399                 scs.WriteLine ("\t\t}\n");
400         }
401
402         public override void WriteType (Type t, string ns, string fn)
403         {
404                 bool bits;
405                 if (!CanMapType (t, out bits))
406                         return;
407
408                 string mtype = Enum.GetUnderlyingType(t).Name;
409                 ObsoleteAttribute oa = (ObsoleteAttribute) Attribute.GetCustomAttribute (t, 
410                                         typeof(ObsoleteAttribute), false);
411                 string obsolete = "";
412                 if (oa != null) {
413                         obsolete = "[Obsolete (\"" + oa.Message + "\")]\n\t\t";
414                 }
415                 scs.WriteLine ("\t\t[DllImport (LIB, " + 
416                         "EntryPoint=\"{0}_From{1}\")]\n" +
417                         "\t\tprivate static extern int From{1} ({1} value, out {2} rval);\n",
418                         ns, t.Name, mtype);
419                 scs.WriteLine ("\t\t{3}public static bool TryFrom{1} ({1} value, out {2} rval)\n" +
420                         "\t\t{{\n" +
421                         "\t\t\treturn From{1} (value, out rval) == 0;\n" +
422                         "\t\t}}\n", ns, t.Name, mtype, obsolete);
423                 scs.WriteLine ("\t\t{2}public static {0} From{1} ({1} value)", mtype, t.Name, obsolete);
424                 scs.WriteLine ("\t\t{");
425                 scs.WriteLine ("\t\t\t{0} rval;", mtype);
426                 scs.WriteLine ("\t\t\tif (From{0} (value, out rval) == -1)\n" + 
427                                 "\t\t\t\tThrowArgumentException (value);", t.Name);
428                 scs.WriteLine ("\t\t\treturn rval;");
429                 scs.WriteLine ("\t\t}\n");
430                 scs.WriteLine ("\t\t[DllImport (LIB, " + 
431                         "EntryPoint=\"{0}_To{1}\")]\n" +
432                         "\t\tprivate static extern int To{1} ({2} value, out {1} rval);\n",
433                         ns, t.Name, mtype);
434                 scs.WriteLine ("\t\t{2}public static bool TryTo{1} ({0} value, out {1} rval)\n" +
435                         "\t\t{{\n" +
436                         "\t\t\treturn To{1} (value, out rval) == 0;\n" +
437                         "\t\t}}\n", mtype, t.Name, obsolete);
438                 scs.WriteLine ("\t\t{2}public static {1} To{1} ({0} value)", mtype, t.Name, obsolete);
439                 scs.WriteLine ("\t\t{");
440                 scs.WriteLine ("\t\t\t{0} rval;", t.Name);
441                 scs.WriteLine ("\t\t\tif (To{0} (value, out rval) == -1)\n" + 
442                                 "\t\t\t\tThrowArgumentException (value);", t.Name);
443                 scs.WriteLine ("\t\t\treturn rval;");
444                 scs.WriteLine ("\t\t}\n");
445         }
446
447         public override void CloseFile (string file_prefix)
448         {
449                 scs.WriteLine ("\t}");
450                 scs.WriteLine ("}\n");
451                 scs.Close ();
452         }
453 }
454
455 class MphPrototypeFileGenerator : FileGenerator {
456         StreamWriter icall;
457         Hashtable methods = new Hashtable ();
458         Hashtable structs = new Hashtable ();
459
460         public override void CreateFile (string assembly_name, string file_prefix)
461         {
462                 icall = File.CreateText (file_prefix + "-icalls.h");
463                 WriteHeader (icall, assembly_name);
464                 icall.WriteLine ("#ifndef INC_Mono_Posix_" + file_prefix + "_ICALLS_H");
465                 icall.WriteLine ("#define INC_Mono_Posix_" + file_prefix + "_ICALLS_H\n");
466                 icall.WriteLine ("#include <glib/gtypes.h>\n");
467                 icall.WriteLine ("G_BEGIN_DECLS\n");
468
469                 // Kill warning about unused method
470                 DumpTypeInfo (null);
471         }
472
473         public override void WriteType (Type t, string ns, string fn)
474         {
475                 BindingFlags bf = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
476                 foreach (MethodInfo m in t.GetMethods (bf)) {
477                         if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0)
478                                 continue;
479                         DllImportAttribute dia = GetDllImportInfo (m);
480                         if (dia == null) {
481                                 Console.WriteLine ("Unable to emit native prototype for P/Invoke " + 
482                                                 "method: {0}", m);
483                                 continue;
484                         }
485                         // we shouldn't declare prototypes for POSIX, etc. functions.
486                         if (dia.Value != "MonoPosixHelper" || IsOnExcludeList (dia.EntryPoint))
487                                 continue;
488                         methods [dia.EntryPoint] = m;
489                         RecordStructs (m);
490                 }
491         }
492
493         private static DllImportAttribute GetDllImportInfo (MethodInfo method)
494         {
495                 // .NET 2.0 synthesizes pseudo-attributes such as DllImport
496                 DllImportAttribute dia = (DllImportAttribute) Attribute.GetCustomAttribute (method, 
497                                         typeof(DllImportAttribute), false);
498                 if (dia != null)
499                         return dia;
500
501                 // We're not on .NET 2.0; assume we're on Mono and use some internal
502                 // methods...
503                 Type MonoMethod = Type.GetType ("System.Reflection.MonoMethod", false);
504                 if (MonoMethod == null) {
505                         Console.WriteLine ("cannot find MonoMethod");
506                         return null;
507                 }
508                 MethodInfo GetDllImportAttribute = 
509                         MonoMethod.GetMethod ("GetDllImportAttribute", 
510                                         BindingFlags.Static | BindingFlags.NonPublic);
511                 if (GetDllImportAttribute == null) {
512                         Console.WriteLine ("cannot find GetDllImportAttribute");
513                         return null;
514                 }
515                 IntPtr mhandle = method.MethodHandle.Value;
516                 return (DllImportAttribute) GetDllImportAttribute.Invoke (null, 
517                                 new object[]{mhandle});
518         }
519
520         private static string[] ExcludeList = new string[]{
521                 "Mono_Posix_Stdlib_snprintf",
522         };
523
524         private bool IsOnExcludeList (string method)
525         {
526                 int idx = Array.BinarySearch (ExcludeList, method);
527                 return (idx >= 0 && idx < ExcludeList.Length) ? true : false;
528         }
529
530         private void RecordStructs (MethodInfo method)
531         {
532                 ParameterInfo[] parameters = method.GetParameters ();
533                 foreach (ParameterInfo pi in parameters) {
534                         string s = GetNativeType (pi.ParameterType);
535                         if (s.StartsWith ("struct"))
536                                 structs [s] = s;
537                 }
538         }
539
540         public override void CloseFile (string file_prefix)
541         {
542                 icall.WriteLine ("/*\n * Structure Declarations\n */");
543                 foreach (string s in Sort (structs.Keys))
544                         icall.WriteLine ("{0};", s.Replace ("*", ""));
545
546                 icall.WriteLine ();
547
548                 icall.WriteLine ("/*\n * Function Declarations\n */");
549                 foreach (string method in Sort (methods.Keys)) {
550                         WriteMethodDeclaration ((MethodInfo) methods [method], method);
551                 }
552
553                 icall.WriteLine ("\nG_END_DECLS\n");
554                 icall.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_ICALLS_H */\n");
555                 icall.Close ();
556         }
557
558         private static IEnumerable Sort (ICollection c)
559         {
560                 ArrayList al = new ArrayList (c);
561                 al.Sort ();
562                 return al;
563         }
564
565         private void WriteMethodDeclaration (MethodInfo method, string entryPoint)
566         {
567                 icall.Write ("{0} ", GetNativeType (method.ReturnType));
568                 icall.Write ("{0} ", entryPoint);
569                 ParameterInfo[] parameters = method.GetParameters();
570                 if (parameters.Length == 0) {
571                         icall.WriteLine ("(void);");
572                         return;
573                 }
574                 if (parameters.Length > 0) {
575                         icall.Write ("(");
576                         WriteParameterDeclaration (parameters [0]);
577                 }
578                 for (int i = 1; i < parameters.Length; ++i) {
579                         icall.Write (", ");
580                         WriteParameterDeclaration (parameters [i]);
581                 }
582                 icall.WriteLine (");");
583         }
584
585         private void DumpTypeInfo (Type t)
586         {
587                 if (t == null)
588                         return;
589
590                 icall.WriteLine ("\t\t/* Type Info for " + t.FullName + ":");
591                 foreach (MemberInfo mi in typeof(Type).GetMembers()) {
592                         icall.WriteLine ("\t\t\t{0}={1}", mi.Name, GetMemberValue (mi, t));
593                 }
594                 icall.WriteLine ("\t\t */");
595         }
596
597         private static string GetMemberValue (MemberInfo mi, Type t)
598         {
599                 try {
600                 switch (mi.MemberType) {
601                         case MemberTypes.Constructor:
602                         case MemberTypes.Method: {
603                                 MethodBase b = (MethodBase) mi;
604                                 if (b.GetParameters().Length == 0)
605                                         return b.Invoke (t, new object[]{}).ToString();
606                                 return "<<cannot invoke>>";
607                         }
608                         case MemberTypes.Field:
609                                 return ((FieldInfo) mi).GetValue (t).ToString ();
610                         case MemberTypes.Property: {
611                                 PropertyInfo pi = (PropertyInfo) mi;
612                                 if (!pi.CanRead)
613                                         return "<<cannot read>>";
614                                 return pi.GetValue (t, null).ToString ();
615                         }
616                         default:
617                                 return "<<unknown value>>";
618                 }
619                 }
620                 catch (Exception e) {
621                         return "<<exception reading member: " + e.Message + ">>";
622                 }
623         }
624
625         private void WriteParameterDeclaration (ParameterInfo pi)
626         {
627                 // DumpTypeInfo (pi.ParameterType);
628                 icall.Write ("{0} {1}", GetNativeType (pi.ParameterType), pi.Name);
629         }
630 }
631
632 // vim: noexpandtab