2 // MakeMap.cs: Builds a C map of constants defined on C# land
5 // Miguel de Icaza (miguel@novell.com)
6 // Jonathan Pryor (jonpryor@vt.edu)
8 // (C) 2003 Novell, Inc.
9 // (C) 2004 Jonathan Pryor
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System.Reflection;
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);
43 public static int Main (string [] args)
45 FileGenerator[] generators = new FileGenerator[]{
46 new HeaderFileGenerator (),
47 new SourceFileGenerator (),
48 new WrapperFileGenerator ()
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);
60 return composite.Run (args);
63 event CreateFileHandler FileCreators;
64 event AssemblyAttributesHandler AssemblyAttributesHandler;
65 event TypeHandler TypeHandler;
66 event CloseFileHandler FileClosers;
68 int Run (string[] args)
70 if (args.Length != 2){
71 Console.WriteLine ("Usage is: make-map assembly output");
75 string assembly_name = args[0];
76 string output = args[1];
78 FileCreators (assembly_name, output);
80 Assembly assembly = Assembly.LoadFrom (assembly_name);
81 AssemblyAttributesHandler (assembly);
83 Type [] exported_types = assembly.GetTypes ();
85 foreach (Type t in exported_types) {
87 if (!CanMapType (t, out bits))
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);
96 TypeHandler (t, ns, fn, etype, bits);
103 static bool CanMapType (Type t, out bool bits)
105 object [] attributes = t.GetCustomAttributes (false);
109 foreach (object attr in attributes) {
110 if (attr.GetType ().Name == "MapAttribute")
112 if (attr.GetType ().Name == "FlagsAttribute")
118 static string GetNativeType (Type t)
120 string ut = Enum.GetUnderlyingType (t).Name;
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";
131 return "int /* **unknown** " + ut + " */";
135 abstract class FileGenerator {
136 public abstract void CreateFile (string assembly_name, string file_prefix);
138 public virtual void WriteAssemblyAttributes (Assembly assembly)
142 public abstract void WriteType (Type t, string ns, string fn, string etype, bool bits);
143 public abstract void CloseFile (string file_prefix);
145 protected static void WriteHeader (StreamWriter s, string assembly)
149 " * This file was automatically generated by make-map from {0}.\n" +
151 " * DO NOT MODIFY.\n" +
153 "#include <config.h>\n",
158 class HeaderFileGenerator : FileGenerator {
161 public override void CreateFile (string assembly_name, string file_prefix)
163 sh = File.CreateText (file_prefix + ".h");
164 WriteHeader (sh, assembly_name);
165 sh.WriteLine ("#ifndef INC_Mono_Posix_" + file_prefix + "_H");
166 sh.WriteLine ("#define INC_Mono_Posix_" + file_prefix + "_H\n");
167 sh.WriteLine ("#include <glib/gtypes.h>\n");
168 sh.WriteLine ("G_BEGIN_DECLS\n");
171 public override void WriteType (Type t, string ns, string fn, string etype, bool bits)
173 WriteLiteralValues (sh, t, fn);
174 sh.WriteLine ("int {1}_From{2} ({0} x, {0} *r);", etype, ns, t.Name);
175 sh.WriteLine ("int {1}_To{2} ({0} x, {0} *r);", etype, ns, t.Name);
179 static void WriteLiteralValues (StreamWriter sh, Type t, string n)
181 object inst = Activator.CreateInstance (t);
182 foreach (FieldInfo fi in t.GetFields ()){
185 sh.WriteLine ("#define {0}_{1} 0x{2:x}", n, fi.Name, fi.GetValue (inst));
189 public override void CloseFile (string file_prefix)
191 sh.WriteLine ("G_END_DECLS\n");
192 sh.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_H */\n");
197 class SourceFileGenerator : FileGenerator {
200 public override void CreateFile (string assembly_name, string file_prefix)
202 sc = File.CreateText (file_prefix + ".c");
203 WriteHeader (sc, assembly_name);
205 if (file_prefix.IndexOf ("/") != -1)
206 file_prefix = file_prefix.Substring (file_prefix.IndexOf ("/") + 1);
207 sc.WriteLine ("#include \"{0}.h\"", file_prefix);
211 public override void WriteAssemblyAttributes (Assembly assembly)
213 object [] x = assembly.GetCustomAttributes (false);
214 Console.WriteLine ("Got: " + x.Length);
215 foreach (object aattr in assembly.GetCustomAttributes (false)) {
216 Console.WriteLine ("Got: " + aattr.GetType ().Name);
217 if (aattr.GetType ().Name == "IncludeAttribute"){
218 WriteDefines (sc, aattr);
219 WriteIncludes (sc, aattr);
224 static void WriteDefines (TextWriter writer, object o)
226 PropertyInfo prop = o.GetType ().GetProperty ("Defines");
228 throw new Exception ("Cannot find 'Defines' property");
230 MethodInfo method = prop.GetGetMethod ();
231 string [] defines = (string []) method.Invoke (o, null);
232 foreach (string def in defines) {
233 writer.WriteLine ("#ifndef {0}", def);
234 writer.WriteLine ("#define {0}", def);
235 writer.WriteLine ("#endif /* ndef {0} */", def);
239 static void WriteIncludes (TextWriter writer, object o)
241 PropertyInfo prop = o.GetType ().GetProperty ("Includes");
243 throw new Exception ("Cannot find 'Includes' property");
245 MethodInfo method = prop.GetGetMethod ();
246 string [] includes = (string []) method.Invoke (o, null);
247 foreach (string inc in includes){
249 string i = inc.Substring (1);
250 writer.WriteLine ("#ifdef HAVE_" + (i.ToUpper ().Replace ("/", "_").Replace (".", "_")));
251 writer.WriteLine ("#include <{0}>", i);
252 writer.WriteLine ("#endif");
254 writer.WriteLine ("#include <{0}>", inc);
259 public override void WriteType (Type t, string ns, string fn, string etype, bool bits)
261 WriteFromManagedType (t, ns, fn, etype, bits);
262 WriteToManagedType (t, ns, fn, etype, bits);
265 private void WriteFromManagedType (Type t, string ns, string fn, string etype, bool bits)
267 sc.WriteLine ("int {1}_From{2} ({0} x, {0} *r)", etype, ns, t.Name);
269 sc.WriteLine ("\t*r = 0;");
270 // For many values, 0 is a valid value, but doesn't have it's own symbol.
271 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
272 // Make 0 valid for all conversions.
273 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
274 foreach (FieldInfo fi in t.GetFields ()) {
278 // properly handle case where [Flags] enumeration has helper
279 // synonyms. e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
280 sc.WriteLine ("\tif ((x & {0}_{1}) == {0}_{1})", fn, fi.Name);
282 sc.WriteLine ("\tif (x == {0}_{1})", fn, fi.Name);
283 sc.WriteLine ("#ifdef {0}", fi.Name);
285 sc.WriteLine ("\t\t*r |= {1};", fn, fi.Name);
287 sc.WriteLine ("\t\t{{*r = {1}; return 0;}}", fn, fi.Name);
288 sc.WriteLine ("#else /* def {0} */\n\t\t{{errno = EINVAL; return -1;}}", fi.Name);
289 sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
292 sc.WriteLine ("\treturn 0;");
294 sc.WriteLine ("\terrno = EINVAL; return -1;"); // return error if not matched
295 sc.WriteLine ("}\n");
298 private void WriteToManagedType (Type t, string ns, string fn, string etype, bool bits)
300 sc.WriteLine ("int {1}_To{2} ({0} x, {0} *r)", etype, ns, t.Name);
302 sc.WriteLine ("\t*r = 0;", etype);
303 // For many values, 0 is a valid value, but doesn't have it's own symbol.
304 // Examples: Error (0 means "no error"), WaitOptions (0 means "no options").
305 // Make 0 valid for all conversions.
306 sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;");
307 foreach (FieldInfo fi in t.GetFields ()) {
310 sc.WriteLine ("#ifdef {0}", fi.Name);
312 // properly handle case where [Flags] enumeration has helper
313 // synonyms. e.g. DEFFILEMODE and ACCESSPERMS for mode_t.
314 sc.WriteLine ("\tif ((x & {1}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name);
316 sc.WriteLine ("\tif (x == {1})\n\t\t{{*r = {0}_{1}; return 0;}}", fn, fi.Name);
317 sc.WriteLine ("#endif /* ndef {0} */", fi.Name);
320 sc.WriteLine ("\treturn 0;");
322 sc.WriteLine ("\terrno = EINVAL; return -1;");
323 sc.WriteLine ("}\n");
326 public override void CloseFile (string file_prefix)
332 class WrapperFileGenerator : FileGenerator {
335 public override void CreateFile (string assembly_name, string file_prefix)
337 scs = File.CreateText (file_prefix + ".cs");
338 WriteHeader (scs, assembly_name);
339 scs.WriteLine ("using System;");
340 scs.WriteLine ("using System.Runtime.InteropServices;");
341 scs.WriteLine ("using Mono.Posix;\n");
342 scs.WriteLine ("namespace Mono.Posix {\n");
343 scs.WriteLine ("\tpublic sealed /* static */ class PosixConvert");
344 scs.WriteLine ("\t{");
345 scs.WriteLine ("\t\tprivate PosixConvert () {}\n");
346 scs.WriteLine ("\t\tprivate const string LIB = \"MonoPosixHelper\";\n");
347 scs.WriteLine ("\t\tprivate static void ThrowArgumentException (object value)");
348 scs.WriteLine ("\t\t{");
349 scs.WriteLine ("\t\t\tthrow new ArgumentOutOfRangeException (\"value\", value,");
350 scs.WriteLine ("\t\t\t\tLocale.GetText (\"Current platform doesn't support this value.\"));");
351 scs.WriteLine ("\t\t}\n");
354 public override void WriteType (Type t, string ns, string fn, string etype, bool bits)
356 string mtype = Enum.GetUnderlyingType(t).Name;
357 scs.WriteLine ("\t\t[DllImport (LIB, " +
358 "EntryPoint=\"{0}_From{1}\")]\n" +
359 "\t\tprivate static extern int From{1} ({1} value, out {2} rval);\n",
361 scs.WriteLine ("\t\tpublic static bool TryFrom{1} ({1} value, out {2} rval)\n" +
363 "\t\t\treturn From{1} (value, out rval) == 0;\n" +
364 "\t\t}}\n", ns, t.Name, mtype);
365 scs.WriteLine ("\t\tpublic static {0} From{1} ({1} value)", mtype, t.Name);
366 scs.WriteLine ("\t\t{");
367 scs.WriteLine ("\t\t\t{0} rval;", mtype);
368 scs.WriteLine ("\t\t\tif (From{0} (value, out rval) == -1)\n" +
369 "\t\t\t\tThrowArgumentException (value);", t.Name);
370 scs.WriteLine ("\t\t\treturn rval;");
371 scs.WriteLine ("\t\t}\n");
372 scs.WriteLine ("\t\t[DllImport (LIB, " +
373 "EntryPoint=\"{0}_To{1}\")]\n" +
374 "\t\tprivate static extern int To{1} ({2} value, out {1} rval);\n",
376 scs.WriteLine ("\t\tpublic static bool TryTo{1} ({0} value, out {1} rval)\n" +
378 "\t\t\treturn To{1} (value, out rval) == 0;\n" +
379 "\t\t}}\n", mtype, t.Name);
380 scs.WriteLine ("\t\tpublic static {1} To{1} ({0} value)", mtype, t.Name);
381 scs.WriteLine ("\t\t{");
382 scs.WriteLine ("\t\t\t{0} rval;", t.Name);
383 scs.WriteLine ("\t\t\tif (To{0} (value, out rval) == -1)\n" +
384 "\t\t\t\tThrowArgumentException (value);", t.Name);
385 scs.WriteLine ("\t\t\treturn rval;");
386 scs.WriteLine ("\t\t}\n");
389 public override void CloseFile (string file_prefix)
391 scs.WriteLine ("\t}");
392 scs.WriteLine ("}\n");