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 string ns
= t
.Namespace
.Replace (".", "_");
92 string etype
= GetNativeType (t
);
94 TypeHandler (t
, ns
, fn
, etype
, bits
);
101 static bool CanMapType (Type t
, out bool bits
)
103 object [] attributes
= t
.GetCustomAttributes (false);
107 foreach (object attr
in attributes
) {
108 if (attr
.GetType ().Name
== "MapAttribute")
110 if (attr
.GetType ().Name
== "FlagsAttribute")
116 static string GetNativeType (Type t
)
118 string ut
= Enum
.GetUnderlyingType (t
).Name
;
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";
129 return "int /* **unknown** " + ut
+ " */";
133 abstract class FileGenerator
{
134 public abstract void CreateFile (string assembly_name
, string file_prefix
);
136 public virtual void WriteAssemblyAttributes (Assembly assembly
)
140 public abstract void WriteType (Type t
, string ns
, string fn
, string etype
, bool bits
);
141 public abstract void CloseFile (string file_prefix
);
143 protected static void WriteHeader (StreamWriter s
, string assembly
)
147 " * This file was automatically generated by make-map from {0}.\n" +
149 " * DO NOT MODIFY.\n" +
154 class HeaderFileGenerator
: FileGenerator
{
157 public override void CreateFile (string assembly_name
, string file_prefix
)
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");
167 public override void WriteType (Type t
, string ns
, string fn
, string etype
, bool bits
)
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
);
175 static void WriteLiteralValues (StreamWriter sh
, Type t
, string n
)
177 object inst
= Activator
.CreateInstance (t
);
178 foreach (FieldInfo fi
in t
.GetFields ()){
181 sh
.WriteLine ("#define {0}_{1} 0x{2:x}", n
, fi
.Name
, fi
.GetValue (inst
));
185 public override void CloseFile (string file_prefix
)
187 sh
.WriteLine ("G_END_DECLS\n");
188 sh
.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix
+ "_H */\n");
193 class SourceFileGenerator
: FileGenerator
{
196 public override void CreateFile (string assembly_name
, string file_prefix
)
198 sc
= File
.CreateText (file_prefix
+ ".c");
199 WriteHeader (sc
, assembly_name
);
201 if (file_prefix
.IndexOf ("/") != -1)
202 file_prefix
= file_prefix
.Substring (file_prefix
.IndexOf ("/") + 1);
203 sc
.WriteLine ("#include \"{0}.h\"", file_prefix
);
207 public override void WriteAssemblyAttributes (Assembly assembly
)
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
);
220 static void WriteDefines (TextWriter writer
, object o
)
222 PropertyInfo prop
= o
.GetType ().GetProperty ("Defines");
224 throw new Exception ("Cannot find 'Defines' property");
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
);
235 static void WriteIncludes (TextWriter writer
, object o
)
237 PropertyInfo prop
= o
.GetType ().GetProperty ("Includes");
239 throw new Exception ("Cannot find 'Includes' property");
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
);
248 public override void WriteType (Type t
, string ns
, string fn
, string etype
, bool bits
)
250 WriteFromManagedType (t
, ns
, fn
, etype
, bits
);
251 WriteToManagedType (t
, ns
, fn
, etype
, bits
);
254 private void WriteFromManagedType (Type t
, string ns
, string fn
, string etype
, bool bits
)
256 sc
.WriteLine ("int {1}_From{2} ({0} x, {0} *r)", etype
, ns
, t
.Name
);
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 ()) {
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
);
271 sc
.WriteLine ("\tif (x == {0}_{1})", fn
, fi
.Name
);
272 sc
.WriteLine ("#ifdef {0}", fi
.Name
);
274 sc
.WriteLine ("\t\t*r |= {1};", fn
, fi
.Name
);
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
);
281 sc
.WriteLine ("\treturn 0;");
283 sc
.WriteLine ("\terrno = EINVAL; return -1;"); // return error if not matched
284 sc
.WriteLine ("}\n");
287 private void WriteToManagedType (Type t
, string ns
, string fn
, string etype
, bool bits
)
289 sc
.WriteLine ("int {1}_To{2} ({0} x, {0} *r)", etype
, ns
, t
.Name
);
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 ()) {
299 sc
.WriteLine ("#ifdef {0}", fi
.Name
);
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
);
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
);
309 sc
.WriteLine ("\treturn 0;");
311 sc
.WriteLine ("\terrno = EINVAL; return -1;");
312 sc
.WriteLine ("}\n");
315 public override void CloseFile (string file_prefix
)
321 class WrapperFileGenerator
: FileGenerator
{
324 public override void CreateFile (string assembly_name
, string file_prefix
)
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");
343 public override void WriteType (Type t
, string ns
, string fn
, string etype
, bool bits
)
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",
350 scs
.WriteLine ("\t\tpublic static bool TryFrom{1} ({1} value, out {2} rval)\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",
365 scs
.WriteLine ("\t\tpublic static bool TryTo{1} ({0} value, out {1} rval)\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");
378 public override void CloseFile (string file_prefix
)
380 scs
.WriteLine ("\t}");
381 scs
.WriteLine ("}\n");