* Makefile: Don't build make-map.exe.
[mono.git] /
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-2005 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.Globalization;
36 using System.Reflection;
37 using System.Runtime.InteropServices;
38
39 delegate void CreateFileHandler (string assembly_name, string file_prefix);
40 delegate void AssemblyAttributesHandler (Assembly assembly);
41 delegate void TypeHandler (Type t, string ns, string fn);
42 delegate void CloseFileHandler (string file_prefix);
43
44 class MakeMap {
45
46         public static int Main (string [] args)
47         {
48                 FileGenerator[] generators = new FileGenerator[]{
49                         new HeaderFileGenerator (),
50                         new SourceFileGenerator (),
51                         new ConvertFileGenerator (),
52                         new ConvertDocFileGenerator (),
53                         new MphPrototypeFileGenerator (),
54                 };
55
56                 MakeMap composite = new MakeMap ();
57                 foreach (FileGenerator g in generators) {
58                         composite.FileCreators += new CreateFileHandler (g.CreateFile);
59                         composite.AssemblyAttributesHandler += 
60                                 new AssemblyAttributesHandler (g.WriteAssemblyAttributes);
61                         composite.TypeHandler += new TypeHandler (g.WriteType);
62                         composite.FileClosers += new CloseFileHandler (g.CloseFile);
63                 }
64
65                 return composite.Run (args);
66         }
67
68         event CreateFileHandler FileCreators;
69         event AssemblyAttributesHandler AssemblyAttributesHandler;
70         event TypeHandler TypeHandler;
71         event CloseFileHandler FileClosers;
72
73         int Run (string[] args)
74         {
75                 if (args.Length != 2){
76                         Console.WriteLine ("Usage is: make-map assembly output");
77                         return 1;
78                 }
79                 
80                 string assembly_name = args[0];
81                 string output = args[1];
82
83                 FileCreators (assembly_name, output);
84
85                 Assembly assembly = Assembly.LoadFrom (assembly_name);
86                 AssemblyAttributesHandler (assembly);
87                 
88                 Type [] exported_types = assembly.GetTypes ();
89                 Array.Sort (exported_types, new TypeFullNameComparer ());
90                         
91                 foreach (Type t in exported_types) {
92                         string ns = t.Namespace;
93                         if (ns == null || !ns.StartsWith ("Mono"))
94                                 continue;
95                         string fn = GetNativeName (t.FullName);
96                         ns = GetNativeName (ns);
97
98                         TypeHandler (t, ns, fn);
99                 }
100                 FileClosers (output);
101
102                 return 0;
103         }
104
105         private class TypeFullNameComparer : IComparer {
106                 public int Compare (object o1, object o2)
107                 {
108                         Type t1 = o1 as Type;
109                         Type t2 = o2 as Type;
110                         if (t1 == t2)
111                                 return 0;
112                         if (t1 == null)
113                                 return 1;
114                         if (t2 == null)
115                                 return -1;
116                         return CultureInfo.InvariantCulture.CompareInfo.Compare (
117                                         t1.FullName, t2.FullName, CompareOptions.Ordinal);
118                 }
119         }
120
121         private class _MemberNameComparer : IComparer {
122                 public int Compare (object o1, object o2)
123                 {
124                         MemberInfo m1 = o1 as MemberInfo;
125                         MemberInfo m2 = o2 as MemberInfo;
126                         if (m1 == m2)
127                                 return 0;
128                         if (m1 == null)
129                                 return 1;
130                         if (m2 == null)
131                                 return -1;
132                         return CultureInfo.InvariantCulture.CompareInfo.Compare (
133                                         m1.Name, m2.Name, CompareOptions.Ordinal);
134                 }
135         }
136
137         private class _OrdinalStringComparer : IComparer {
138                 public int Compare (object o1, object o2)
139                 {
140                         string s1 = o1 as string;
141                         string s2 = o2 as string;
142                         if (object.ReferenceEquals (s1, s2))
143                                 return 0;
144                         if (s1 == null)
145                                 return 1;
146                         if (s2 == null)
147                                 return -1;
148                         return CultureInfo.InvariantCulture.CompareInfo.Compare (s1, s2, 
149                                         CompareOptions.Ordinal);
150                 }
151         }
152
153         internal static IComparer MemberNameComparer = new _MemberNameComparer ();
154         internal static IComparer OrdinalStringComparer = new _OrdinalStringComparer ();
155
156         internal static string GetNativeName (string fn)
157         {
158                 fn = fn.Replace ('.', '_');
159                 if (fn.StartsWith ("Mono_Unix_Native"))
160                         return fn.Replace ("Mono_Unix_Native", "Mono_Posix");
161                 return fn.Replace ("Mono_Unix", "Mono_Posix");
162         }
163 }
164
165 abstract class FileGenerator {
166         public abstract void CreateFile (string assembly_name, string file_prefix);
167
168         public virtual void WriteAssemblyAttributes (Assembly assembly)
169         {
170         }
171
172         public abstract void WriteType (Type t, string ns, string fn);
173         public abstract void CloseFile (string file_prefix);
174
175         protected static void WriteHeader (StreamWriter s, string assembly)
176         {
177                 WriteHeader (s, assembly, false);
178         }
179
180         protected static void WriteHeader (StreamWriter s, string assembly, bool noConfig)
181         {
182                 s.WriteLine (
183                         "/*\n" +
184                         " * This file was automatically generated by make-map from {0}.\n" +
185                         " *\n" +
186                         " * DO NOT MODIFY.\n" +
187                         " */",
188                         assembly);
189                 if (!noConfig) {
190                         s.WriteLine ("#include <config.h>");
191                 }
192                 s.WriteLine ();
193         }
194
195         protected static bool CanMapType (Type t, out bool bits)
196         {
197                 object [] attributes = t.GetCustomAttributes (false);
198                 bool map = false;
199                 bits = false;
200                 
201                 foreach (object attr in attributes) {
202                         if (attr.GetType ().Name == "MapAttribute")
203                                 map = true;
204                         if (attr.GetType ().Name == "FlagsAttribute")
205                                 bits = true;
206                 }
207                 return map;
208         }
209
210         protected static string GetNativeType (Type t)
211         {
212                 string ut = t.Name;
213                 if (t.IsEnum)
214                         ut = Enum.GetUnderlyingType (t).Name;
215                 Type et = t.GetElementType ();
216                 if (et != null && et.IsEnum)
217                         ut = Enum.GetUnderlyingType (et).Name;
218
219                 string type = null;
220
221                 switch (ut) {
222                         case "Boolean":       type = "int";             break;
223                         case "Byte":          type = "unsigned char";   break;
224                         case "SByte":         type = "signed char";     break;
225                         case "Int16":         type = "short";           break;
226                         case "UInt16":        type = "unsigned short";  break;
227                         case "Int32":         type = "int";             break;
228                         case "UInt32":        type = "unsigned int";    break;
229                         case "UInt32[]":      type = "unsigned int*";   break;
230                         case "Int64":         type = "gint64";          break;
231                         case "UInt64":        type = "guint64";         break;
232                         case "IntPtr":        type = "void*";           break;
233                         case "Byte[]":        type = "void*";           break;
234                         case "String":        type = "const char*";     break;
235                         case "StringBuilder": type = "char*";           break;
236                         case "Void":          type = "void";            break;
237                         case "HandleRef":     type = "void*";           break;
238                 }
239                 if (type != null)
240                         return string.Format ("{0}{1}", type,
241                                         t.IsByRef ? "*" : "");
242                 return GetTypeName (t);
243         }
244
245         private static string GetTypeName (Type t)
246         {
247                 if (t.Namespace.StartsWith ("System"))
248                         return "int /* warning: unknown mapping for type: " + t.Name + " */";
249                 string ts = "struct " +
250                         MakeMap.GetNativeName (t.FullName).Replace ("+", "_").Replace ("&", "*")
251                                 .Replace ("[]", "*");
252                 return ts;
253         }
254 }
255
256 class HeaderFileGenerator : FileGenerator {
257         StreamWriter sh;
258
259         public override void CreateFile (string assembly_name, string file_prefix)
260         {
261                 sh = File.CreateText (file_prefix + ".h");
262                 WriteHeader (sh, assembly_name);
263                 sh.WriteLine ("#ifndef INC_Mono_Posix_" + file_prefix + "_H");
264                 sh.WriteLine ("#define INC_Mono_Posix_" + file_prefix + "_H\n");
265                 sh.WriteLine ("#include <glib.h>\n");
266                 sh.WriteLine ("G_BEGIN_DECLS\n");
267         }
268
269         public override void WriteType (Type t, string ns, string fn)
270         {
271                 bool bits;
272                 if (!CanMapType (t, out bits))
273                         return;
274                 string etype = GetNativeType (t);
275
276                 WriteLiteralValues (sh, t, fn);
277                 sh.WriteLine ("int {1}_From{2} ({0} x, {0} *r);", etype, ns, t.Name);
278                 sh.WriteLine ("int {1}_To{2} ({0} x, {0} *r);", etype, ns, t.Name);
279                 sh.WriteLine ();
280         }
281
282         static void WriteLiteralValues (StreamWriter sh, Type t, string n)
283         {
284                 object inst = Activator.CreateInstance (t);
285                 FieldInfo[] fields = t.GetFields ();
286                 Array.Sort (fields, MakeMap.MemberNameComparer);
287                 foreach (FieldInfo fi in fields) {
288                         if (!fi.IsLiteral)
289                                 continue;
290                         sh.WriteLine ("#define {0}_{1} 0x{2:x}", n, fi.Name, fi.GetValue (inst));
291                 }
292         }
293
294         public override void CloseFile (string file_prefix)
295         {
296                 sh.WriteLine ("G_END_DECLS\n");
297                 sh.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_H */\n");
298                 sh.Close ();
299         }
300 }
301
302 class SourceFileGenerator : FileGenerator {
303         StreamWriter sc;
304
305         public override void CreateFile (string assembly_name, string file_prefix)
306         {
307                 sc = File.CreateText (file_prefix + ".c");
308                 WriteHeader (sc, assembly_name);
309
310                 if (file_prefix.IndexOf ("/") != -1)
311                         file_prefix = file_prefix.Substring (file_prefix.IndexOf ("/") + 1);
312                 sc.WriteLine ("#include \"{0}.h\"", file_prefix);
313                 sc.WriteLine ();
314         }
315
316         public override void WriteAssemblyAttributes (Assembly assembly)
317         {
318                 object [] x = assembly.GetCustomAttributes (false);
319                 Console.WriteLine ("Got: " + x.Length);
320                 foreach (object aattr in assembly.GetCustomAttributes (false)) {
321                         Console.WriteLine ("Got: " + aattr.GetType ().Name);
322                         if (aattr.GetType ().Name == "HeaderAttribute"){
323                                 WriteDefines (sc, aattr);
324                                 WriteIncludes (sc, aattr);
325                         }
326                 }
327         }
328
329         static void WriteDefines (TextWriter writer, object o)
330         {
331                 PropertyInfo prop = o.GetType ().GetProperty ("Defines");
332                 if (prop == null)
333                         throw new Exception ("Cannot find 'Defines' property");
334
335                 MethodInfo method = prop.GetGetMethod ();
336                 string [] defines = method.Invoke (o, null).ToString ().Split (',');
337                 foreach (string def in defines) {
338                         writer.WriteLine ("#ifndef {0}", def);
339                         writer.WriteLine ("#define {0}", def);
340                         writer.WriteLine ("#endif /* ndef {0} */", def);
341                 }
342         }
343
344         static void WriteIncludes (TextWriter writer, object o)
345         {
346                 PropertyInfo prop = o.GetType ().GetProperty ("Includes");
347                 if (prop == null)
348                         throw new Exception ("Cannot find 'Includes' property");
349
350                 MethodInfo method = prop.GetGetMethod ();
351                 string [] includes = method.Invoke (o, null).ToString ().Split (',');;
352                 foreach (string inc in includes){
353                         if (inc.Length > 3 && 
354                                         string.CompareOrdinal (inc, 0, "ah:", 0, 3) == 0) {
355                                 string i = inc.Substring (3);
356                                 writer.WriteLine ("#ifdef HAVE_" + (i.ToUpper ().Replace ("/", "_").Replace (".", "_")));
357                                 writer.WriteLine ("#include <{0}>", i);
358                                 writer.WriteLine ("#endif");
359                         } else 
360                                 writer.WriteLine ("#include <{0}>", inc);
361                 }
362                 writer.WriteLine ();
363         }
364
365         public override void WriteType (Type t, string ns, string fn)
366         {
367                 bool bits;
368                 if (!CanMapType (t, out bits))
369                         return;
370                 string etype = GetNativeType (t);
371
372                 WriteFromManagedType (t, ns, fn, etype, bits);
373                 WriteToManagedType (t, ns, fn, etype, bits);
374         }
375
376         private void WriteFromManagedType (Type t, string ns, string fn, string etype, bool bits)
377         {
378                 sc.WriteLine ("int {1}_From{2} ({0} x, {0} *r)", etype, ns, t.Name);
379                 sc.WriteLine ("{");
380                 sc.WriteLine ("\t*r = 0;");
381                 // For many values, 0 is a valid value, but doesn't have it's own symbol.
382                 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
383                 // Make 0 valid for all conversions.
384                 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
385                 FieldInfo[] fields = t.GetFields ();
386                 Array.Sort (fields, MakeMap.MemberNameComparer);
387                 foreach (FieldInfo fi in fields) {
388                         if (!fi.IsLiteral)
389                                 continue;
390                         if (Attribute.GetCustomAttribute (fi, 
391                                 typeof(ObsoleteAttribute), false) != null) {
392                                 sc.WriteLine ("\t/* {0}_{1} is obsolete; ignoring */", fn, fi.Name);
393                                 continue;
394                         }
395                         if (bits)
396                                 // properly handle case where [Flags] enumeration has helper
397                                 // synonyms.  e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
398                                 sc.WriteLine ("\tif ((x & {0}_{1}) == {0}_{1})", fn, fi.Name);
399                         else
400                                 sc.WriteLine ("\tif (x == {0}_{1})", fn, fi.Name);
401                         sc.WriteLine ("#ifdef {0}", fi.Name);
402                         if (bits)
403                                 sc.WriteLine ("\t\t*r |= {1};", fn, fi.Name);
404                         else
405                                 sc.WriteLine ("\t\t{{*r = {1}; return 0;}}", fn, fi.Name);
406                         sc.WriteLine ("#else /* def {0} */\n\t\t{{errno = EINVAL; return -1;}}", fi.Name);
407                         sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
408                 }
409                 if (bits)
410                         sc.WriteLine ("\treturn 0;");
411                 else
412                         sc.WriteLine ("\terrno = EINVAL; return -1;"); // return error if not matched
413                 sc.WriteLine ("}\n");
414         }
415
416         private void WriteToManagedType (Type t, string ns, string fn, string etype, bool bits)
417         {
418                 sc.WriteLine ("int {1}_To{2} ({0} x, {0} *r)", etype, ns, t.Name);
419                 sc.WriteLine ("{");
420                 sc.WriteLine ("\t*r = 0;", etype);
421                 // For many values, 0 is a valid value, but doesn't have it's own symbol.
422                 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
423                 // Make 0 valid for all conversions.
424                 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
425                 FieldInfo[] fields = t.GetFields ();
426                 Array.Sort (fields, MakeMap.MemberNameComparer);
427                 foreach (FieldInfo fi in fields) {
428                         if (!fi.IsLiteral)
429                                 continue;
430                         sc.WriteLine ("#ifdef {0}", fi.Name);
431                         if (bits)
432                                 // properly handle case where [Flags] enumeration has helper
433                                 // synonyms.  e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
434                                 sc.WriteLine ("\tif ((x & {1}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name);
435                         else
436                                 sc.WriteLine ("\tif (x == {1})\n\t\t{{*r = {0}_{1}; return 0;}}", fn, fi.Name);
437                         sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
438                 }
439                 if (bits)
440                         sc.WriteLine ("\treturn 0;");
441                 else
442                         sc.WriteLine ("\terrno = EINVAL; return -1;");
443                 sc.WriteLine ("}\n");
444         }
445
446         public override void CloseFile (string file_prefix)
447         {
448                 sc.Close ();
449         }
450 }
451
452 class ConvertFileGenerator : FileGenerator {
453         StreamWriter scs;
454
455         public override void CreateFile (string assembly_name, string file_prefix)
456         {
457                 scs = File.CreateText (file_prefix + ".cs");
458                 WriteHeader (scs, assembly_name, true);
459                 scs.WriteLine ("using System;");
460                 scs.WriteLine ("using System.Runtime.InteropServices;");
461                 scs.WriteLine ("using Mono.Unix.Native;\n");
462                 scs.WriteLine ("namespace Mono.Unix.Native {\n");
463                 scs.WriteLine ("\t[CLSCompliant (false)]");
464                 scs.WriteLine ("\tpublic sealed /* static */ partial class NativeConvert");
465                 scs.WriteLine ("\t{");
466                 scs.WriteLine ("\t\tprivate NativeConvert () {}\n");
467                 scs.WriteLine ("\t\tprivate const string LIB = \"MonoPosixHelper\";\n");
468                 scs.WriteLine ("\t\tprivate static void ThrowArgumentException (object value)");
469                 scs.WriteLine ("\t\t{");
470                 scs.WriteLine ("\t\t\tthrow new ArgumentOutOfRangeException (\"value\", value,");
471                 scs.WriteLine ("\t\t\t\tLocale.GetText (\"Current platform doesn't support this value.\"));");
472                 scs.WriteLine ("\t\t}\n");
473         }
474
475         public override void WriteType (Type t, string ns, string fn)
476         {
477                 bool bits;
478                 if (!CanMapType (t, out bits))
479                         return;
480
481                 string mtype = Enum.GetUnderlyingType(t).Name;
482                 ObsoleteAttribute oa = (ObsoleteAttribute) Attribute.GetCustomAttribute (t, 
483                                         typeof(ObsoleteAttribute), false);
484                 string obsolete = "";
485                 if (oa != null) {
486                         obsolete = string.Format ("[Obsolete (\"{0}\", {1})]\n\t\t",
487                                         oa.Message, oa.IsError ? "true" : "false");
488                 }
489                 scs.WriteLine ("\t\t{3}[DllImport (LIB, " + 
490                         "EntryPoint=\"{0}_From{1}\")]\n" +
491                         "\t\tprivate static extern int From{1} ({1} value, out {2} rval);\n",
492                         ns, t.Name, mtype, obsolete);
493                 scs.WriteLine ("\t\t{3}public static bool TryFrom{1} ({1} value, out {2} rval)\n" +
494                         "\t\t{{\n" +
495                         "\t\t\treturn From{1} (value, out rval) == 0;\n" +
496                         "\t\t}}\n", ns, t.Name, mtype, obsolete);
497                 scs.WriteLine ("\t\t{2}public static {0} From{1} ({1} value)", mtype, t.Name, obsolete);
498                 scs.WriteLine ("\t\t{");
499                 scs.WriteLine ("\t\t\t{0} rval;", mtype);
500                 scs.WriteLine ("\t\t\tif (From{0} (value, out rval) == -1)\n" + 
501                                 "\t\t\t\tThrowArgumentException (value);", t.Name);
502                 scs.WriteLine ("\t\t\treturn rval;");
503                 scs.WriteLine ("\t\t}\n");
504                 scs.WriteLine ("\t\t{3}[DllImport (LIB, " + 
505                         "EntryPoint=\"{0}_To{1}\")]\n" +
506                         "\t\tprivate static extern int To{1} ({2} value, out {1} rval);\n",
507                         ns, t.Name, mtype, obsolete);
508                 scs.WriteLine ("\t\t{2}public static bool TryTo{1} ({0} value, out {1} rval)\n" +
509                         "\t\t{{\n" +
510                         "\t\t\treturn To{1} (value, out rval) == 0;\n" +
511                         "\t\t}}\n", mtype, t.Name, obsolete);
512                 scs.WriteLine ("\t\t{2}public static {1} To{1} ({0} value)", mtype, t.Name, obsolete);
513                 scs.WriteLine ("\t\t{");
514                 scs.WriteLine ("\t\t\t{0} rval;", t.Name);
515                 scs.WriteLine ("\t\t\tif (To{0} (value, out rval) == -1)\n" + 
516                                 "\t\t\t\tThrowArgumentException (value);", t.Name);
517                 scs.WriteLine ("\t\t\treturn rval;");
518                 scs.WriteLine ("\t\t}\n");
519         }
520
521         public override void CloseFile (string file_prefix)
522         {
523                 scs.WriteLine ("\t}");
524                 scs.WriteLine ("}\n");
525                 scs.Close ();
526         }
527 }
528
529 class ConvertDocFileGenerator : FileGenerator {
530         StreamWriter scs;
531
532         public override void CreateFile (string assembly_name, string file_prefix)
533         {
534                 scs = File.CreateText (file_prefix + ".xml");
535                 scs.WriteLine ("    <!-- BEGIN GENERATED CONTENT");
536                 WriteHeader (scs, assembly_name, true);
537                 scs.WriteLine ("      -->");
538         }
539
540         public override void WriteType (Type t, string ns, string fn)
541         {
542                 bool bits;
543                 if (!CanMapType (t, out bits))
544                         return;
545
546                 string type = GetCSharpType (t);
547                 string mtype = Enum.GetUnderlyingType(t).FullName;
548                 string member = t.Name;
549                 string ftype = t.FullName;
550
551                 string to_returns = "";
552                 string to_remarks = "";
553                 string to_exception = "";
554
555                 if (bits) {
556                         to_returns = "<returns>An approximation of the equivalent managed value.</returns>";
557                         to_remarks = @"<para>The current conversion functions are unable to determine
558         if a value in a <c>[Flags]</c>-marked enumeration <i>does not</i> 
559         exist on the current platform.  As such, if <paramref name=""value"" /> 
560         contains a flag value which the current platform doesn't support, it 
561         will not be present in the managed value returned.</para>
562         <para>This should only be a problem if <paramref name=""value"" /> 
563         <i>was not</i> previously returned by 
564         <see cref=""M:Mono.Unix.Native.NativeConvert.From" + member + "\" />.</para>\n";
565                 }
566                 else {
567                         to_returns = "<returns>The equivalent managed value.</returns>";
568                         to_exception = @"
569         <exception cref=""T:System.ArgumentOutOfRangeException"">
570           <paramref name=""value"" /> has no equivalent managed value.
571         </exception>
572 ";
573                 }
574                 scs.WriteLine (@"
575     <Member MemberName=""TryFrom{1}"">
576       <MemberSignature Language=""C#"" Value=""public static bool TryFrom{1} ({0} value, out {2} rval);"" />
577       <MemberType>Method</MemberType>
578       <ReturnValue>
579         <ReturnType>System.Boolean</ReturnType>
580       </ReturnValue>
581       <Parameters>
582         <Parameter Name=""value"" Type=""{0}"" />
583         <Parameter Name=""rval"" Type=""{3}&amp;"" RefType=""out"" />
584       </Parameters>
585       <Docs>
586         <param name=""value"">The managed value to convert.</param>
587         <param name=""rval"">The OS-specific equivalent value.</param>
588         <summary>Converts a <see cref=""T:{0}"" /> 
589           enumeration value to an OS-specific value.</summary>
590         <returns><see langword=""true"" /> if the conversion was successful; 
591         otherwise, <see langword=""false"" />.</returns>
592         <remarks><para>This is an exception-safe alternative to 
593         <see cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" />.</para>
594         <para>If successful, this method stores the OS-specific equivalent
595         value of <paramref name=""value"" /> into <paramref name=""rval"" />.
596         Otherwise, <paramref name=""rval"" /> will contain <c>0</c>.</para>
597         </remarks>
598         <altmember cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" />
599         <altmember cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" />
600         <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryTo{1}"" />
601       </Docs>
602     </Member>
603     <Member MemberName=""From{1}"">
604       <MemberSignature Language=""C#"" Value=""public static {2} From{1} ({0} value);"" />
605       <MemberType>Method</MemberType>
606       <ReturnValue>
607         <ReturnType>{3}</ReturnType>
608       </ReturnValue>
609       <Parameters>
610         <Parameter Name=""value"" Type=""{0}"" />
611       </Parameters>
612       <Docs>
613         <param name=""value"">The managed value to convert.</param>
614         <summary>Converts a <see cref=""T:{0}"" /> 
615           to an OS-specific value.</summary>
616         <returns>The equivalent OS-specific value.</returns>
617         <exception cref=""T:System.ArgumentOutOfRangeException"">
618           <paramref name=""value"" /> has no equivalent OS-specific value.
619         </exception>
620         <remarks></remarks>
621         <altmember cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" />
622         <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryFrom{1}"" />
623         <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryTo{1}"" />
624       </Docs>
625     </Member>
626     <Member MemberName=""TryTo{1}"">
627       <MemberSignature Language=""C#"" Value=""public static bool TryTo{1} ({2} value, out {0} rval);"" />
628       <MemberType>Method</MemberType>
629       <ReturnValue>
630         <ReturnType>System.Boolean</ReturnType>
631       </ReturnValue>
632       <Parameters>
633         <Parameter Name=""value"" Type=""{3}"" />
634         <Parameter Name=""rval"" Type=""{0}&amp;"" RefType=""out"" />
635       </Parameters>
636       <Docs>
637         <param name=""value"">The OS-specific value to convert.</param>
638         <param name=""rval"">The managed equivalent value</param>
639         <summary>Converts an OS-specific value to a 
640           <see cref=""T:{0}"" />.</summary>
641         <returns><see langword=""true"" /> if the conversion was successful; 
642         otherwise, <see langword=""false"" />.</returns>
643         <remarks><para>This is an exception-safe alternative to 
644         <see cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" />.</para>
645         <para>If successful, this method stores the managed equivalent
646         value of <paramref name=""value"" /> into <paramref name=""rval"" />.
647         Otherwise, <paramref name=""rval"" /> will contain a <c>0</c>
648         cast to a <see cref=""T:{0}"" />.</para>
649         " + to_remarks + 
650 @"        </remarks>
651         <altmember cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" />
652         <altmember cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" />
653         <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryFrom{1}"" />
654       </Docs>
655     </Member>
656     <Member MemberName=""To{1}"">
657       <MemberSignature Language=""C#"" Value=""public static {0} To{1} ({2} value);"" />
658       <MemberType>Method</MemberType>
659       <ReturnValue>
660         <ReturnType>{0}</ReturnType>
661       </ReturnValue>
662       <Parameters>
663         <Parameter Name=""value"" Type=""{3}"" />
664       </Parameters>
665       <Docs>
666         <param name=""value"">The OS-specific value to convert.</param>
667         <summary>Converts an OS-specific value to a 
668           <see cref=""T:{0}"" />.</summary>
669                                         " + to_returns + "\n" + 
670                         to_exception + 
671 @"        <remarks>
672         " + to_remarks + @"
673         </remarks>
674         <altmember cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" />
675         <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryFrom{1}"" />
676         <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryTo{1}"" />
677       </Docs>
678     </Member>
679 ", ftype, member, type, mtype
680                 );
681         }
682
683         private string GetCSharpType (Type t)
684         {
685                 string ut = t.Name;
686                 if (t.IsEnum)
687                         ut = Enum.GetUnderlyingType (t).Name;
688                 Type et = t.GetElementType ();
689                 if (et != null && et.IsEnum)
690                         ut = Enum.GetUnderlyingType (et).Name;
691
692                 string type = null;
693
694                 switch (ut) {
695                         case "Boolean":       type = "bool";    break;
696                         case "Byte":          type = "byte";    break;
697                         case "SByte":         type = "sbyte";   break;
698                         case "Int16":         type = "short";   break;
699                         case "UInt16":        type = "ushort";  break;
700                         case "Int32":         type = "int";     break;
701                         case "UInt32":        type = "uint";    break;
702                         case "Int64":         type = "long";    break;
703                         case "UInt64":        type = "ulong";   break;
704                 }
705
706                 return type;
707         }
708
709         public override void CloseFile (string file_prefix)
710         {
711                 scs.WriteLine ("    <!-- END GENERATED CONTENT -->");
712                 scs.Close ();
713         }
714 }
715
716 class MphPrototypeFileGenerator : FileGenerator {
717         StreamWriter icall;
718         Hashtable methods = new Hashtable ();
719         Hashtable structs = new Hashtable ();
720
721         public override void CreateFile (string assembly_name, string file_prefix)
722         {
723                 icall = File.CreateText (file_prefix + "-icalls.h");
724                 WriteHeader (icall, assembly_name);
725                 icall.WriteLine ("#ifndef INC_Mono_Posix_" + file_prefix + "_ICALLS_H");
726                 icall.WriteLine ("#define INC_Mono_Posix_" + file_prefix + "_ICALLS_H\n");
727                 icall.WriteLine ("#include <glib.h>\n");
728                 icall.WriteLine ("G_BEGIN_DECLS\n");
729
730                 // Kill warning about unused method
731                 DumpTypeInfo (null);
732         }
733
734         public override void WriteType (Type t, string ns, string fn)
735         {
736                 BindingFlags bf = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
737                 foreach (MethodInfo m in t.GetMethods (bf)) {
738                         if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0)
739                                 continue;
740                         DllImportAttribute dia = GetDllImportInfo (m);
741                         if (dia == null) {
742                                 Console.WriteLine ("Unable to emit native prototype for P/Invoke " + 
743                                                 "method: {0}", m);
744                                 continue;
745                         }
746                         // we shouldn't declare prototypes for POSIX, etc. functions.
747                         if (dia.Value != "MonoPosixHelper" || IsOnExcludeList (dia.EntryPoint))
748                                 continue;
749                         methods [dia.EntryPoint] = m;
750                         RecordStructs (m);
751                 }
752         }
753
754         private static DllImportAttribute GetDllImportInfo (MethodInfo method)
755         {
756                 // .NET 2.0 synthesizes pseudo-attributes such as DllImport
757                 DllImportAttribute dia = (DllImportAttribute) Attribute.GetCustomAttribute (method, 
758                                         typeof(DllImportAttribute), false);
759                 if (dia != null)
760                         return dia;
761
762                 // We're not on .NET 2.0; assume we're on Mono and use some internal
763                 // methods...
764                 Type MonoMethod = Type.GetType ("System.Reflection.MonoMethod", false);
765                 if (MonoMethod == null) {
766                         Console.WriteLine ("cannot find MonoMethod");
767                         return null;
768                 }
769                 MethodInfo GetDllImportAttribute = 
770                         MonoMethod.GetMethod ("GetDllImportAttribute", 
771                                         BindingFlags.Static | BindingFlags.NonPublic);
772                 if (GetDllImportAttribute == null) {
773                         Console.WriteLine ("cannot find GetDllImportAttribute");
774                         return null;
775                 }
776                 IntPtr mhandle = method.MethodHandle.Value;
777                 return (DllImportAttribute) GetDllImportAttribute.Invoke (null, 
778                                 new object[]{mhandle});
779         }
780
781         private static string[] ExcludeList = new string[]{
782                 "Mono_Posix_Stdlib_snprintf",
783         };
784
785         private bool IsOnExcludeList (string method)
786         {
787                 int idx = Array.BinarySearch (ExcludeList, method);
788                 return (idx >= 0 && idx < ExcludeList.Length) ? true : false;
789         }
790
791         private void RecordStructs (MethodInfo method)
792         {
793                 ParameterInfo[] parameters = method.GetParameters ();
794                 foreach (ParameterInfo pi in parameters) {
795                         string s = GetNativeType (pi.ParameterType);
796                         if (s.StartsWith ("struct"))
797                                 structs [s] = s;
798                 }
799         }
800
801         public override void CloseFile (string file_prefix)
802         {
803                 icall.WriteLine ("/*\n * Structure Declarations\n */");
804                 foreach (string s in Sort (structs.Keys))
805                         icall.WriteLine ("{0};", s.Replace ("*", ""));
806
807                 icall.WriteLine ();
808
809                 icall.WriteLine ("/*\n * Function Declarations\n */");
810                 foreach (string method in Sort (methods.Keys)) {
811                         WriteMethodDeclaration ((MethodInfo) methods [method], method);
812                 }
813
814                 icall.WriteLine ("\nG_END_DECLS\n");
815                 icall.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_ICALLS_H */\n");
816                 icall.Close ();
817         }
818
819         private static IEnumerable Sort (ICollection c)
820         {
821                 ArrayList al = new ArrayList (c);
822                 al.Sort (MakeMap.OrdinalStringComparer);
823                 return al;
824         }
825
826         private void WriteMethodDeclaration (MethodInfo method, string entryPoint)
827         {
828                 icall.Write ("{0} ", GetNativeType (method.ReturnType));
829                 icall.Write ("{0} ", entryPoint);
830                 ParameterInfo[] parameters = method.GetParameters();
831                 if (parameters.Length == 0) {
832                         icall.WriteLine ("(void);");
833                         return;
834                 }
835                 if (parameters.Length > 0) {
836                         icall.Write ("(");
837                         WriteParameterDeclaration (parameters [0]);
838                 }
839                 for (int i = 1; i < parameters.Length; ++i) {
840                         icall.Write (", ");
841                         WriteParameterDeclaration (parameters [i]);
842                 }
843                 icall.WriteLine (");");
844         }
845
846         private void DumpTypeInfo (Type t)
847         {
848                 if (t == null)
849                         return;
850
851                 icall.WriteLine ("\t\t/* Type Info for " + t.FullName + ":");
852                 foreach (MemberInfo mi in typeof(Type).GetMembers()) {
853                         icall.WriteLine ("\t\t\t{0}={1}", mi.Name, GetMemberValue (mi, t));
854                 }
855                 icall.WriteLine ("\t\t */");
856         }
857
858         private static string GetMemberValue (MemberInfo mi, Type t)
859         {
860                 try {
861                 switch (mi.MemberType) {
862                         case MemberTypes.Constructor:
863                         case MemberTypes.Method: {
864                                 MethodBase b = (MethodBase) mi;
865                                 if (b.GetParameters().Length == 0)
866                                         return b.Invoke (t, new object[]{}).ToString();
867                                 return "<<cannot invoke>>";
868                         }
869                         case MemberTypes.Field:
870                                 return ((FieldInfo) mi).GetValue (t).ToString ();
871                         case MemberTypes.Property: {
872                                 PropertyInfo pi = (PropertyInfo) mi;
873                                 if (!pi.CanRead)
874                                         return "<<cannot read>>";
875                                 return pi.GetValue (t, null).ToString ();
876                         }
877                         default:
878                                 return "<<unknown value>>";
879                 }
880                 }
881                 catch (Exception e) {
882                         return "<<exception reading member: " + e.Message + ">>";
883                 }
884         }
885
886         private void WriteParameterDeclaration (ParameterInfo pi)
887         {
888                 // DumpTypeInfo (pi.ParameterType);
889                 icall.Write ("{0} {1}", GetNativeType (pi.ParameterType), pi.Name);
890         }
891 }
892
893 // vim: noexpandtab