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