* Stdlib.cs: Add more <stdio.h> wrappers, such as fread(3) and fwrite(3).
[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.IO;
34 using System.Reflection;
35
36 delegate void CreateFileHandler (string assembly_name, string file_prefix);
37 delegate void AssemblyAttributesHandler (Assembly assembly);
38 delegate void TypeHandler (Type t, string ns, string fn, string etype, bool bits);
39 delegate void CloseFileHandler (string file_prefix);
40
41 class MakeMap {
42
43         public static int Main (string [] args)
44         {
45                 FileGenerator[] generators = new FileGenerator[]{
46                         new HeaderFileGenerator (),
47                         new SourceFileGenerator (),
48                         new WrapperFileGenerator ()
49                 };
50
51                 MakeMap composite = new MakeMap ();
52                 foreach (FileGenerator g in generators) {
53                         composite.FileCreators += new CreateFileHandler (g.CreateFile);
54                         composite.AssemblyAttributesHandler += 
55                                 new AssemblyAttributesHandler (g.WriteAssemblyAttributes);
56                         composite.TypeHandler += new TypeHandler (g.WriteType);
57                         composite.FileClosers += new CloseFileHandler (g.CloseFile);
58                 }
59
60                 return composite.Run (args);
61         }
62
63         event CreateFileHandler FileCreators;
64         event AssemblyAttributesHandler AssemblyAttributesHandler;
65         event TypeHandler TypeHandler;
66         event CloseFileHandler FileClosers;
67
68         int Run (string[] args)
69         {
70                 if (args.Length != 2){
71                         Console.WriteLine ("Usage is: make-map assembly output");
72                         return 1;
73                 }
74                 
75                 string assembly_name = args[0];
76                 string output = args[1];
77
78                 FileCreators (assembly_name, output);
79
80                 Assembly assembly = Assembly.LoadFrom (assembly_name);
81                 AssemblyAttributesHandler (assembly);
82                 
83                 Type [] exported_types = assembly.GetTypes ();
84                         
85                 foreach (Type t in exported_types) {
86                         bool bits;
87                         if (!CanMapType (t, out bits))
88                                 continue;
89
90                         string fn = t.FullName.Replace (".", "_");
91                         string ns = t.Namespace.Replace (".", "_");
92       string etype = GetNativeType (t);
93
94                         TypeHandler (t, ns, fn, etype, bits);
95                 }
96                 FileClosers (output);
97
98                 return 0;
99         }
100
101         static bool CanMapType (Type t, out bool bits)
102         {
103                 object [] attributes = t.GetCustomAttributes (false);
104                 bool map = false;
105                 bits = false;
106                 
107                 foreach (object attr in attributes) {
108                         if (attr.GetType ().Name == "MapAttribute")
109                                 map = true;
110                         if (attr.GetType ().Name == "FlagsAttribute")
111                                 bits = true;
112                 }
113                 return map;
114         }
115
116         static string GetNativeType (Type t)
117         {
118                 string ut = Enum.GetUnderlyingType (t).Name;
119                 switch (ut) {
120                         case "Byte":   return "unsigned char";
121                         case "SByte":  return "signed char";
122                         case "Int16":  return "short";
123                         case "UInt16": return "unsigned short";
124                         case "Int32":  return "int";
125                         case "UInt32": return "unsigned int";
126                         case "Int64":  return "gint64";
127                         case "UInt64": return "guint64";
128                 }
129                 return "int /* **unknown** " + ut + " */";
130         }
131 }
132
133 abstract class FileGenerator {
134         public abstract void CreateFile (string assembly_name, string file_prefix);
135
136         public virtual void WriteAssemblyAttributes (Assembly assembly)
137         {
138         }
139
140         public abstract void WriteType (Type t, string ns, string fn, string etype, bool bits);
141         public abstract void CloseFile (string file_prefix);
142
143         protected static void WriteHeader (StreamWriter s, string assembly)
144         {
145                 s.WriteLine (
146                         "/*\n" +
147                         " * This file was automatically generated by make-map from {0}.\n" +
148                         " *\n" +
149                         " * DO NOT MODIFY.\n" +
150                         " */\n", assembly);
151         }
152 }
153
154 class HeaderFileGenerator : FileGenerator {
155         StreamWriter sh;
156
157         public override void CreateFile (string assembly_name, string file_prefix)
158         {
159                 sh = File.CreateText (file_prefix + ".h");
160                 WriteHeader (sh, assembly_name);
161                 sh.WriteLine ("#ifndef INC_Mono_Posix_" + file_prefix + "_H");
162                 sh.WriteLine ("#define INC_Mono_Posix_" + file_prefix + "_H\n");
163                 sh.WriteLine ("#include <glib/gtypes.h>\n");
164                 sh.WriteLine ("G_BEGIN_DECLS\n");
165         }
166
167         public override void WriteType (Type t, string ns, string fn, string etype, bool bits)
168         {
169                 WriteLiteralValues (sh, t, fn);
170                 sh.WriteLine ("int {1}_From{2} ({0} x, {0} *r);", etype, ns, t.Name);
171                 sh.WriteLine ("int {1}_To{2} ({0} x, {0} *r);", etype, ns, t.Name);
172                 sh.WriteLine ();
173         }
174
175         static void WriteLiteralValues (StreamWriter sh, Type t, string n)
176         {
177                 object inst = Activator.CreateInstance (t);
178                 foreach (FieldInfo fi in t.GetFields ()){
179                         if (!fi.IsLiteral)
180                                 continue;
181                         sh.WriteLine ("#define {0}_{1} 0x{2:x}", n, fi.Name, fi.GetValue (inst));
182                 }
183         }
184
185         public override void CloseFile (string file_prefix)
186         {
187                 sh.WriteLine ("G_END_DECLS\n");
188                 sh.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_H */\n");
189                 sh.Close ();
190         }
191 }
192
193 class SourceFileGenerator : FileGenerator {
194         StreamWriter sc;
195
196         public override void CreateFile (string assembly_name, string file_prefix)
197         {
198                 sc = File.CreateText (file_prefix + ".c");
199                 WriteHeader (sc, assembly_name);
200
201                 if (file_prefix.IndexOf ("/") != -1)
202                         file_prefix = file_prefix.Substring (file_prefix.IndexOf ("/") + 1);
203                 sc.WriteLine ("#include \"{0}.h\"", file_prefix);
204                 sc.WriteLine ();
205         }
206
207         public override void WriteAssemblyAttributes (Assembly assembly)
208         {
209                 object [] x = assembly.GetCustomAttributes (false);
210                 Console.WriteLine ("Got: " + x.Length);
211                 foreach (object aattr in assembly.GetCustomAttributes (false)) {
212                         Console.WriteLine ("Got: " + aattr.GetType ().Name);
213                         if (aattr.GetType ().Name == "IncludeAttribute"){
214                                 WriteDefines (sc, aattr);
215                                 WriteIncludes (sc, aattr);
216                         }
217                 }
218         }
219
220         static void WriteDefines (TextWriter writer, object o)
221         {
222                 PropertyInfo prop = o.GetType ().GetProperty ("Defines");
223                 if (prop == null)
224                         throw new Exception ("Cannot find 'Defines' property");
225
226                 MethodInfo method = prop.GetGetMethod ();
227                 string [] defines = (string []) method.Invoke (o, null);
228                 foreach (string def in defines) {
229                         writer.WriteLine ("#ifndef {0}", def);
230                         writer.WriteLine ("#define {0}", def);
231                         writer.WriteLine ("#endif /* ndef {0} */", def);
232                 }
233         }
234
235         static void WriteIncludes (TextWriter writer, object o)
236         {
237                 PropertyInfo prop = o.GetType ().GetProperty ("Includes");
238                 if (prop == null)
239                         throw new Exception ("Cannot find 'Includes' property");
240
241                 MethodInfo method = prop.GetGetMethod ();
242                 string [] includes = (string []) method.Invoke (o, null);
243                 foreach (string inc in includes)
244                         writer.WriteLine ("#include <{0}>", inc);
245                 writer.WriteLine ();
246         }
247
248         public override void WriteType (Type t, string ns, string fn, string etype, bool bits)
249         {
250                 WriteFromManagedType (t, ns, fn, etype, bits);
251                 WriteToManagedType (t, ns, fn, etype, bits);
252         }
253
254         private void WriteFromManagedType (Type t, string ns, string fn, string etype, bool bits)
255         {
256                 sc.WriteLine ("int {1}_From{2} ({0} x, {0} *r)", etype, ns, t.Name);
257                 sc.WriteLine ("{");
258                 sc.WriteLine ("\t*r = 0;");
259                 // For many values, 0 is a valid value, but doesn't have it's own symbol.
260                 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
261                 // Make 0 valid for all conversions.
262                 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
263                 foreach (FieldInfo fi in t.GetFields ()) {
264                         if (!fi.IsLiteral)
265                                 continue;
266                         if (bits)
267                                 // properly handle case where [Flags] enumeration has helper
268                                 // synonyms.  e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
269                                 sc.WriteLine ("\tif ((x & {0}_{1}) == {0}_{1})", fn, fi.Name);
270                         else
271                                 sc.WriteLine ("\tif (x == {0}_{1})", fn, fi.Name);
272                         sc.WriteLine ("#ifdef {0}", fi.Name);
273                         if (bits)
274                                 sc.WriteLine ("\t\t*r |= {1};", fn, fi.Name);
275                         else
276                                 sc.WriteLine ("\t\t{{*r = {1}; return 0;}}", fn, fi.Name);
277                         sc.WriteLine ("#else /* def {0} */\n\t\t{{errno = EINVAL; return -1;}}", fi.Name);
278                         sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
279                 }
280                 if (bits)
281                         sc.WriteLine ("\treturn 0;");
282                 else
283                         sc.WriteLine ("\terrno = EINVAL; return -1;"); // return error if not matched
284                 sc.WriteLine ("}\n");
285         }
286
287         private void WriteToManagedType (Type t, string ns, string fn, string etype, bool bits)
288         {
289                 sc.WriteLine ("int {1}_To{2} ({0} x, {0} *r)", etype, ns, t.Name);
290                 sc.WriteLine ("{");
291                 sc.WriteLine ("\t*r = 0;", etype);
292                 // For many values, 0 is a valid value, but doesn't have it's own symbol.
293                 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
294                 // Make 0 valid for all conversions.
295                 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
296                 foreach (FieldInfo fi in t.GetFields ()) {
297                         if (!fi.IsLiteral)
298                                 continue;
299                         sc.WriteLine ("#ifdef {0}", fi.Name);
300                         if (bits)
301                                 // properly handle case where [Flags] enumeration has helper
302                                 // synonyms.  e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
303                                 sc.WriteLine ("\tif ((x & {1}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name);
304                         else
305                                 sc.WriteLine ("\tif (x == {1})\n\t\t{{*r = {0}_{1}; return 0;}}", fn, fi.Name);
306                         sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
307                 }
308                 if (bits)
309                         sc.WriteLine ("\treturn 0;");
310                 else
311                         sc.WriteLine ("\terrno = EINVAL; return -1;");
312                 sc.WriteLine ("}\n");
313         }
314
315         public override void CloseFile (string file_prefix)
316         {
317                 sc.Close ();
318         }
319 }
320
321 class WrapperFileGenerator : FileGenerator {
322         StreamWriter scs;
323
324         public override void CreateFile (string assembly_name, string file_prefix)
325         {
326                 scs = File.CreateText (file_prefix + ".cs");
327                 WriteHeader (scs, assembly_name);
328                 scs.WriteLine ("using System;");
329                 scs.WriteLine ("using System.Runtime.InteropServices;");
330                 scs.WriteLine ("using Mono.Posix;\n");
331                 scs.WriteLine ("namespace Mono.Posix {\n");
332                 scs.WriteLine ("\tpublic sealed /* static */ class PosixConvert");
333                 scs.WriteLine ("\t{");
334                 scs.WriteLine ("\t\tprivate PosixConvert () {}\n");
335                 scs.WriteLine ("\t\tprivate const string LIB = \"MonoPosixHelper\";\n");
336                 scs.WriteLine ("\t\tprivate static void ThrowArgumentException (object value)");
337                 scs.WriteLine ("\t\t{");
338                 scs.WriteLine ("\t\t\tthrow new ArgumentOutOfRangeException (\"value\", value,");
339                 scs.WriteLine ("\t\t\t\tLocale.GetText (\"Current platform doesn't support this value.\"));");
340                 scs.WriteLine ("\t\t}\n");
341         }
342
343         public override void WriteType (Type t, string ns, string fn, string etype, bool bits)
344         {
345                 string mtype = Enum.GetUnderlyingType(t).Name;
346                 scs.WriteLine ("\t\t[DllImport (LIB, " + 
347                         "EntryPoint=\"{0}_From{1}\")]\n" +
348                         "\t\tprivate static extern int From{1} ({1} value, out {2} rval);\n",
349                         ns, t.Name, mtype);
350                 scs.WriteLine ("\t\tpublic static bool TryFrom{1} ({1} value, out {2} rval)\n" +
351                         "\t\t{{\n" +
352                         "\t\t\treturn From{1} (value, out rval) == 0;\n" +
353                         "\t\t}}\n", ns, t.Name, mtype);
354                 scs.WriteLine ("\t\tpublic static {0} From{1} ({1} value)", mtype, t.Name);
355                 scs.WriteLine ("\t\t{");
356                 scs.WriteLine ("\t\t\t{0} rval;", mtype);
357                 scs.WriteLine ("\t\t\tif (From{0} (value, out rval) == -1)\n" + 
358                                 "\t\t\t\tThrowArgumentException (value);", t.Name);
359                 scs.WriteLine ("\t\t\treturn rval;");
360                 scs.WriteLine ("\t\t}\n");
361                 scs.WriteLine ("\t\t[DllImport (LIB, " + 
362                         "EntryPoint=\"{0}_To{1}\")]\n" +
363                         "\t\tprivate static extern int To{1} ({2} value, out {1} rval);\n",
364                         ns, t.Name, mtype);
365                 scs.WriteLine ("\t\tpublic static bool TryTo{1} ({0} value, out {1} rval)\n" +
366                         "\t\t{{\n" +
367                         "\t\t\treturn To{1} (value, out rval) == 0;\n" +
368                         "\t\t}}\n", mtype, t.Name);
369                 scs.WriteLine ("\t\tpublic static {1} To{1} ({0} value)", mtype, t.Name);
370                 scs.WriteLine ("\t\t{");
371                 scs.WriteLine ("\t\t\t{0} rval;", t.Name);
372                 scs.WriteLine ("\t\t\tif (To{0} (value, out rval) == -1)\n" + 
373                                 "\t\t\t\tThrowArgumentException (value);", t.Name);
374                 scs.WriteLine ("\t\t\treturn rval;");
375                 scs.WriteLine ("\t\t}\n");
376         }
377
378         public override void CloseFile (string file_prefix)
379         {
380                 scs.WriteLine ("\t}");
381                 scs.WriteLine ("}\n");
382                 scs.Close ();
383         }
384 }
385
386 // vim: noexpandtab