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