// // create-native-map.cs: Builds a C map of constants defined on C# land // // Authors: // Miguel de Icaza (miguel@novell.com) // Jonathan Pryor (jonpryor@vt.edu) // // (C) 2003 Novell, Inc. // (C) 2004-2005 Jonathan Pryor // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.IO; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using Mono.Fuse.NETStandard; delegate void CreateFileHandler (string assembly_name, string file_prefix); delegate void AssemblyAttributesHandler (Assembly assembly); delegate void TypeHandler (Type t, string ns, string fn); delegate void CloseFileHandler (string file_prefix); namespace CreateNativeMap { internal class MakeMap { public static int Main(string[] args) { FileGenerator[] generators = new FileGenerator[] { new HeaderFileGenerator(), new SourceFileGenerator(), new ConvertFileGenerator(), new ConvertDocFileGenerator(), }; Configuration config = new Configuration(); bool exit = false; try { exit = !config.Parse(args); } catch (Exception e) { Console.WriteLine("{0}: error: {1}", Environment.GetCommandLineArgs()[0], e.Message); exit = true; } if (exit) { Configuration.ShowHelp(); return 1; } MapUtils.config = config; MakeMap composite = new MakeMap(); foreach (FileGenerator g in generators) { g.Configuration = config; composite.FileCreators += new CreateFileHandler(g.CreateFile); composite.AssemblyAttributesHandler += new AssemblyAttributesHandler(g.WriteAssemblyAttributes); composite.TypeHandler += new TypeHandler(g.WriteType); composite.FileClosers += new CloseFileHandler(g.CloseFile); } return composite.Run(config); } event CreateFileHandler FileCreators; event AssemblyAttributesHandler AssemblyAttributesHandler; event TypeHandler TypeHandler; event CloseFileHandler FileClosers; int Run(Configuration config) { FileCreators(config.AssemblyFileName, config.OutputPrefix); Assembly assembly = Assembly.LoadFrom(config.AssemblyFileName); AssemblyAttributesHandler(assembly); Type[] exported_types = assembly.GetTypes(); Array.Sort(exported_types, new TypeFullNameComparer()); foreach (Type t in exported_types) { string ns = MapUtils.GetNamespace(t); /* if (ns == null || !ns.StartsWith ("Mono")) continue; */ string fn = MapUtils.GetManagedType(t); TypeHandler(t, ns, fn); } FileClosers(config.OutputPrefix); return 0; } private class TypeFullNameComparer : IComparer { public int Compare(Type t1, Type t2) { if (t1 == t2) return 0; if (t1 == null) return 1; if (t2 == null) return -1; return CultureInfo.InvariantCulture.CompareInfo.Compare( t1.FullName, t2.FullName, CompareOptions.Ordinal); } } } class Configuration { Dictionary renameMembers = new Dictionary(); Dictionary renameNamespaces = new Dictionary(); List libraries = new List(); List optionals = new List(); List excludes = new List(); List iheaders = new List(); List pheaders = new List(); List imacros = new List(); List pmacros = new List(); string assembly_name; string output; delegate void ArgumentHandler(Configuration c, string name, string value); static Dictionary handlers; static Configuration() { handlers = new Dictionary(); handlers["autoconf-header"] = delegate(Configuration c, string name, string value) { c.iheaders.Add("ah:" + name); }; handlers["autoconf-member"] = delegate(Configuration c, string name, string value) { c.optionals.Add(name); }; handlers["impl-header"] = delegate(Configuration c, string name, string value) { c.iheaders.Add(name); }; handlers["impl-macro"] = delegate(Configuration c, string name, string value) { if (value != null) name += "=" + value; c.imacros.Add(name); }; handlers["library"] = delegate(Configuration c, string name, string value) { c.libraries.Add(name); }; handlers["exclude-native-symbol"] = delegate(Configuration c, string name, string value) { c.excludes.Add(name); }; handlers["public-header"] = delegate(Configuration c, string name, string value) { c.pheaders.Add(name); }; handlers["public-macro"] = delegate(Configuration c, string name, string value) { if (value != null) name += "=" + value; c.pmacros.Add(name); }; handlers["rename-member"] = delegate(Configuration c, string name, string value) { if (value == null) { throw new Exception("missing rename value"); } c.renameMembers[name] = value; }; handlers["rename-namespace"] = delegate(Configuration c, string name, string value) { if (value == null) { throw new Exception("missing rename value"); } value = value.Replace(".", "_"); c.renameNamespaces[name] = value; }; } public Configuration() { } public List NativeLibraries { get { return libraries; } } public List AutoconfMembers { get { return optionals; } } public List NativeExcludeSymbols { get { return excludes; } } public List PublicHeaders { get { return pheaders; } } public List PublicMacros { get { return pmacros; } } public List ImplementationHeaders { get { return iheaders; } } public List ImplementationMacros { get { return imacros; } } public IDictionary MemberRenames { get { return renameMembers; } } public IDictionary NamespaceRenames { get { return renameNamespaces; } } public string AssemblyFileName { get { return assembly_name; } } public string OutputPrefix { get { return output; } } const string NameValue = @"(?[^=]+)(=(?.*))?"; const string Argument = @"^--(?[\w-]+)([=:]" + NameValue + ")?$"; public bool Parse(string[] args) { Regex argRE = new Regex(Argument); Regex valRE = new Regex(NameValue); for (int i = 0; i < args.Length; ++i) { Match m = argRE.Match(args[i]); if (m.Success) { string arg = m.Groups["Argument"].Value; if (arg == "help") return false; if (!m.Groups["Name"].Success) { if ((i + 1) >= args.Length) throw new Exception( string.Format("missing value for argument {0}", args[i])); m = valRE.Match(args[++i]); if (!m.Success) { throw new Exception( string.Format("invalid value for argument {0}: {1}", args[i - 1], args[i])); } } string name = m.Groups["Name"].Value; string value = m.Groups["Value"].Success ? m.Groups["Value"].Value : null; if (handlers.ContainsKey(arg)) { handlers[arg](this, name, value); } else { throw new Exception("invalid argument " + arg); } } else if (assembly_name == null) { assembly_name = args[i]; } else { output = args[i]; } } if (assembly_name == null) throw new Exception("missing ASSEMBLY"); if (output == null) throw new Exception("missing OUTPUT-PREFIX"); libraries.Sort(); optionals.Sort(); excludes.Sort(); return true; } public static void ShowHelp() { Console.WriteLine( "Usage: create-native-map \n" + "\t[--autoconf-header=HEADER]* \n" + "\t[--autoconf-member=MEMBER]* \n" + "\t[--exclude-native-symbol=SYMBOL]*\n" + "\t[--impl-header=HEADER]* \n" + "\t[--impl-macro=MACRO]* \n" + "\t[--library=LIBRARY]+ \n" + "\t[--public-header=HEADER]* \n" + "\t[--public-macro=MACRO]* \n" + "\t[--rename-member=FROM=TO]* \n" + "\t[--rename-namespace=FROM=TO]*\n" + "\tASSEMBLY OUTPUT-PREFIX" ); } } static class MapUtils { internal static Configuration config; public static T GetCustomAttribute(MemberInfo element) where T : Attribute { return (T) Attribute.GetCustomAttribute(element, typeof(T), true); } public static T GetCustomAttribute(Assembly assembly) where T : Attribute { return (T) Attribute.GetCustomAttribute(assembly, typeof(T), true); } public static T[] GetCustomAttributes(MemberInfo element) where T : Attribute { return (T[]) Attribute.GetCustomAttributes(element, typeof(T), true); } public static T[] GetCustomAttributes(Assembly assembly) where T : Attribute { return (T[]) Attribute.GetCustomAttributes(assembly, typeof(T), true); } public static MapAttribute GetMapAttribute(ICustomAttributeProvider element) { foreach (object o in element.GetCustomAttributes(true)) { if (!IsMapAttribute(o)) continue; string nativeType = GetPropertyValueAsString(o, "NativeType"); MapAttribute map = nativeType == null ? new MapAttribute() : new MapAttribute(nativeType); map.SuppressFlags = GetPropertyValueAsString(o, "SuppressFlags"); return map; } return null; } private static bool IsMapAttribute(object o) { Type t = o.GetType(); do { if (t.Name == "MapAttribute") { return true; } t = t.BaseType; } while (t != null); return false; } private static string GetPropertyValueAsString(object o, string property) { object v = GetPropertyValue(o, property); string s = v == null ? null : v.ToString(); if (s != null) return s.Length == 0 ? null : s; return null; } private static object GetPropertyValue(object o, string property) { PropertyInfo p = o.GetType().GetProperty(property); if (p == null) return null; if (!p.CanRead) return null; return p.GetValue(o, new object[0]); } public static bool IsIntegralType(Type t) { return t == typeof(byte) || t == typeof(sbyte) || t == typeof(char) || t == typeof(short) || t == typeof(ushort) || t == typeof(int) || t == typeof(uint) || t == typeof(long) || t == typeof(ulong); } public static bool IsBlittableType(Type t) { return IsIntegralType(t) || t == typeof(IntPtr) || t == typeof(UIntPtr); } public static string GetNativeType(Type t) { Type et = GetElementType(t); string ut = et.Name; if (et.IsEnum) ut = Enum.GetUnderlyingType(et).Name; string type = null; switch (ut) { case "Boolean": type = "int"; break; case "Byte": type = "unsigned char"; break; case "SByte": type = "signed char"; break; case "Int16": type = "short"; break; case "UInt16": type = "unsigned short"; break; case "Int32": type = "int"; break; case "UInt32": type = "unsigned int"; break; case "Int64": type = "gint64"; break; case "UInt64": type = "guint64"; break; case "IntPtr": type = "void*"; break; case "UIntPtr": type = "void*"; break; case "String": type = "const char"; break; /* ref type */ case "StringBuilder": type = "char"; break; /* ref type */ case "Void": type = "void"; break; case "HandleRef": type = "void*"; break; } bool isDelegate = IsDelegate(t); if (type == null) type = isDelegate ? t.Name : GetStructName(t); if (!et.IsValueType && !isDelegate) { type += "*"; } while (t.HasElementType) { t = t.GetElementType(); type += "*"; } return type; //return (t.IsByRef || t.IsArray || (!t.IsValueType && !isDelegate)) ? type + "*" : type; } public static bool IsDelegate(Type t) { return typeof(Delegate).IsAssignableFrom(t); } private static string GetStructName(Type t) { t = GetElementType(t); return "struct " + GetManagedType(t); } public static Type GetElementType(Type t) { while (t.HasElementType) { t = t.GetElementType(); } return t; } public static string GetNamespace(Type t) { if (t.Namespace == null) return ""; if (config.NamespaceRenames.ContainsKey(t.Namespace)) return config.NamespaceRenames[t.Namespace]; return t.Namespace.Replace('.', '_'); } public static string GetManagedType(Type t) { string ns = GetNamespace(t); string tn = (t.DeclaringType != null ? t.DeclaringType.Name + "_" : "") + t.Name; return ns + "_" + tn; } public static string GetNativeType(FieldInfo field) { MapAttribute map = GetMapAttribute(field) ?? GetMapAttribute(field.FieldType); if (map != null) return map.NativeType; return null; } public static string GetFunctionDeclaration(string name, MethodInfo method) { StringBuilder sb = new StringBuilder(); #if false Console.WriteLine (t); foreach (object o in t.GetMembers ()) Console.WriteLine ("\t" + o); #endif sb.Append(method.ReturnType == typeof(string) ? "char*" : MapUtils.GetNativeType(method.ReturnType)); sb.Append(" ").Append(name).Append(" ("); ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0) { sb.Append("void"); } else { if (parameters.Length > 0) { WriteParameterDeclaration(sb, parameters[0]); } for (int i = 1; i < parameters.Length; ++i) { sb.Append(", "); WriteParameterDeclaration(sb, parameters[i]); } } sb.Append(")"); return sb.ToString(); } private static void WriteParameterDeclaration(StringBuilder sb, ParameterInfo pi) { // DumpTypeInfo (pi.ParameterType); string nt = GetNativeType(pi.ParameterType); sb.AppendFormat("{0} {1}", nt, pi.Name); } internal class _MemberNameComparer : IComparer, IComparer { public int Compare(FieldInfo m1, FieldInfo m2) { return Compare((MemberInfo) m1, (MemberInfo) m2); } public int Compare(MemberInfo m1, MemberInfo m2) { if (m1 == m2) return 0; if (m1 == null) return 1; if (m2 == null) return -1; return CultureInfo.InvariantCulture.CompareInfo.Compare( m1.Name, m2.Name, CompareOptions.Ordinal); } } private class _OrdinalStringComparer : IComparer { public int Compare(string s1, string s2) { if (object.ReferenceEquals(s1, s2)) return 0; if (s1 == null) return 1; if (s2 == null) return -1; return CultureInfo.InvariantCulture.CompareInfo.Compare(s1, s2, CompareOptions.OrdinalIgnoreCase); } } internal static _MemberNameComparer MemberNameComparer = new _MemberNameComparer(); internal static IComparer OrdinalStringComparer = new _OrdinalStringComparer(); } abstract class FileGenerator { private Configuration config; public Configuration Configuration { get { return config; } set { config = value; } } public abstract void CreateFile(string assembly_name, string file_prefix); public virtual void WriteAssemblyAttributes(Assembly assembly) { } public abstract void WriteType(Type t, string ns, string fn); public abstract void CloseFile(string file_prefix); protected static void WriteHeader(StreamWriter s, string assembly) { WriteHeader(s, assembly, false); } protected static void WriteHeader(StreamWriter s, string assembly, bool noConfig) { s.WriteLine( "/*\n" + " * This file was automatically generated by create-native-map from {0}.\n" + " *\n" + " * DO NOT MODIFY.\n" + " */", assembly); if (!noConfig) { s.WriteLine("#ifdef HAVE_CONFIG_H"); s.WriteLine("#include "); s.WriteLine("#endif /* ndef HAVE_CONFIG_H */"); } s.WriteLine(); } protected static bool CanMapType(Type t) { return MapUtils.GetMapAttribute(t) != null; } protected static bool IsFlagsEnum(Type t) { return t.IsEnum && MapUtils.GetCustomAttributes(t).Length > 0; } protected static void SortFieldsInOffsetOrder(Type t, FieldInfo[] fields) { Array.Sort(fields, delegate(FieldInfo f1, FieldInfo f2) { long o1 = (long) Marshal.OffsetOf(f1.DeclaringType, f1.Name); long o2 = (long) Marshal.OffsetOf(f2.DeclaringType, f2.Name); return o1.CompareTo(o2); }); } protected static void WriteMacroDefinition(TextWriter writer, string macro) { if (macro == null || macro.Length == 0) return; string[] val = macro.Split('='); writer.WriteLine("#ifndef {0}", val[0]); writer.WriteLine("#define {0}{1}", val[0], val.Length > 1 ? " " + val[1] : ""); writer.WriteLine("#endif /* ndef {0} */", val[0]); writer.WriteLine(); } private static Regex includeRegex = new Regex(@"^(?ah:)?(?(""|<)(?.*)(""|>))$"); protected static void WriteIncludeDeclaration(TextWriter writer, string inc) { if (inc == null || inc.Length == 0) return; Match m = includeRegex.Match(inc); if (!m.Groups["Include"].Success) { Console.WriteLine("warning: invalid PublicIncludeFile: {0}", inc); return; } if (m.Success && m.Groups["AutoHeader"].Success) { string i = m.Groups["IncludeFile"].Value; string def = "HAVE_" + i.ToUpper().Replace("/", "_").Replace(".", "_"); writer.WriteLine("#ifdef {0}", def); writer.WriteLine("#include {0}", m.Groups["Include"]); writer.WriteLine("#endif /* ndef {0} */", def); } else writer.WriteLine("#include {0}", m.Groups["Include"]); } protected string GetNativeMemberName(FieldInfo field) { if (!Configuration.MemberRenames.ContainsKey(field.Name)) return field.Name; return Configuration.MemberRenames[field.Name]; } } class HeaderFileGenerator : FileGenerator { StreamWriter sh; string assembly_file; Dictionary methods = new Dictionary(); Dictionary structs = new Dictionary(); Dictionary delegates = new Dictionary(); List decls = new List(); public override void CreateFile(string assembly_name, string file_prefix) { sh = File.CreateText(file_prefix + ".h"); file_prefix = file_prefix.Replace("../", "").Replace("/", "_"); this.assembly_file = assembly_name = Path.GetFileName(assembly_name); WriteHeader(sh, assembly_name, true); assembly_name = assembly_name.Replace(".dll", "").Replace(".", "_"); sh.WriteLine("#ifndef INC_" + assembly_name + "_" + file_prefix + "_H"); sh.WriteLine("#define INC_" + assembly_name + "_" + file_prefix + "_H\n"); sh.WriteLine("#include \n"); sh.WriteLine("G_BEGIN_DECLS\n"); // Kill warning about unused method DumpTypeInfo(null); } public override void WriteAssemblyAttributes(Assembly assembly) { sh.WriteLine("/*\n * Public Macros\n */"); foreach (string def in Configuration.PublicMacros) { WriteMacroDefinition(sh, def); } sh.WriteLine(); sh.WriteLine("/*\n * Public Includes\n */"); foreach (string inc in Configuration.PublicHeaders) { WriteIncludeDeclaration(sh, inc); } sh.WriteLine(); sh.WriteLine("/*\n * Enumerations\n */"); } public override void WriteType(Type t, string ns, string fn) { WriteEnum(t, ns, fn); CacheStructs(t, ns, fn); CacheExternalMethods(t, ns, fn); } private void WriteEnum(Type t, string ns, string fn) { if (!CanMapType(t) || !t.IsEnum) return; string etype = MapUtils.GetNativeType(t); WriteLiteralValues(sh, t, fn); sh.WriteLine("int {1}_From{2} ({0} x, {0} *r);", etype, ns, t.Name); sh.WriteLine("int {1}_To{2} ({0} x, {0} *r);", etype, ns, t.Name); Configuration.NativeExcludeSymbols.Add( string.Format("{1}_From{2}", etype, ns, t.Name)); Configuration.NativeExcludeSymbols.Add( string.Format("{1}_To{2}", etype, ns, t.Name)); Configuration.NativeExcludeSymbols.Sort(); sh.WriteLine(); } static void WriteLiteralValues(StreamWriter sh, Type t, string n) { object inst = Activator.CreateInstance(t); int max_field_length = 0; FieldInfo[] fields = t.GetFields(); Array.Sort(fields, delegate(FieldInfo f1, FieldInfo f2) { max_field_length = Math.Max(max_field_length, f1.Name.Length); max_field_length = Math.Max(max_field_length, f2.Name.Length); return MapUtils.MemberNameComparer.Compare(f1, f2); }); max_field_length += 1 + n.Length; sh.WriteLine("enum {0} {{", n); foreach (FieldInfo fi in fields) { if (!fi.IsLiteral) continue; string e = n + "_" + fi.Name; sh.WriteLine("\t{0,-" + max_field_length + "} = 0x{1:x},", e, fi.GetValue(inst)); sh.WriteLine("\t#define {0,-" + max_field_length + "} {0}", e); } sh.WriteLine("};"); } private void CacheStructs(Type t, string ns, string fn) { if (t.IsEnum) return; MapAttribute map = MapUtils.GetMapAttribute(t); if (map != null) { if (map.NativeType != null && map.NativeType.Length > 0) decls.Add(map.NativeType); RecordTypes(t); } } private void CacheExternalMethods(Type t, string ns, string fn) { BindingFlags bf = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; foreach (MethodInfo m in t.GetMethods(bf)) { if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) continue; DllImportAttribute dia = GetDllImportInfo(m); if (dia == null) { Console.WriteLine("warning: unable to emit native prototype for P/Invoke " + "method: {0}", m); continue; } // we shouldn't declare prototypes for POSIX, etc. functions. if (Configuration.NativeLibraries.BinarySearch(dia.Value) < 0 || IsOnExcludeList(dia.EntryPoint)) continue; methods[dia.EntryPoint] = m; RecordTypes(m); } } private static DllImportAttribute GetDllImportInfo(MethodInfo method) { // .NET 2.0 synthesizes pseudo-attributes such as DllImport DllImportAttribute dia = MapUtils.GetCustomAttribute(method); if (dia != null) return dia; // We're not on .NET 2.0; assume we're on Mono and use some internal // methods... Type MonoMethod = Type.GetType("System.Reflection.MonoMethod", false); if (MonoMethod == null) { Console.WriteLine("warning: cannot find MonoMethod"); return null; } MethodInfo GetDllImportAttribute = MonoMethod.GetMethod("GetDllImportAttribute", BindingFlags.Static | BindingFlags.NonPublic); if (GetDllImportAttribute == null) { Console.WriteLine("warning: cannot find GetDllImportAttribute"); return null; } IntPtr mhandle = method.MethodHandle.Value; return (DllImportAttribute) GetDllImportAttribute.Invoke(null, new object[] {mhandle}); } private bool IsOnExcludeList(string method) { int idx = Configuration.NativeExcludeSymbols.BinarySearch(method); return (idx < 0) ? false : true; } private void RecordTypes(MethodInfo method) { ParameterInfo[] parameters = method.GetParameters(); foreach (ParameterInfo pi in parameters) { RecordTypes(pi.ParameterType); } } private void RecordTypes(Type st) { if (typeof(Delegate).IsAssignableFrom(st) && !delegates.ContainsKey(st.Name)) { MethodInfo mi = st.GetMethod("Invoke"); delegates[st.Name] = mi; RecordTypes(mi); return; } Type et = MapUtils.GetElementType(st); string s = MapUtils.GetNativeType(et); if (s.StartsWith("struct ") && !structs.ContainsKey(et.FullName)) { structs[et.FullName] = et; foreach (FieldInfo fi in et.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { RecordTypes(fi.FieldType); } } } public override void CloseFile(string file_prefix) { IEnumerable structures = Sort(structs.Keys); sh.WriteLine(); sh.WriteLine("/*\n * Managed Structure Declarations\n */\n"); foreach (string s in structures) { sh.WriteLine("struct {0};", MapUtils.GetManagedType(structs[s])); } sh.WriteLine(); sh.WriteLine("/*\n * Inferred Structure Declarations\n */\n"); foreach (string s in decls) { sh.WriteLine("{0};", s); } sh.WriteLine(); sh.WriteLine("/*\n * Delegate Declarations\n */\n"); foreach (string s in Sort(delegates.Keys)) { sh.WriteLine("typedef {0};", MapUtils.GetFunctionDeclaration("(*" + s + ")", delegates[s])); } sh.WriteLine(); sh.WriteLine("/*\n * Structures\n */\n"); foreach (string s in structures) { WriteStructDeclarations(s); } sh.WriteLine(); sh.WriteLine("/*\n * Functions\n */"); foreach (string method in Configuration.NativeExcludeSymbols) { if (methods.ContainsKey(method)) methods.Remove(method); } foreach (string method in Sort(methods.Keys)) { WriteMethodDeclaration((MethodInfo) methods[method], method); } sh.WriteLine("\nG_END_DECLS\n"); sh.WriteLine("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_H */\n"); sh.Close(); } private static IEnumerable Sort(ICollection c) { List al = new List(c); al.Sort(MapUtils.OrdinalStringComparer); return al; } private void WriteStructDeclarations(string s) { Type t = structs[s]; #if false if (!t.Assembly.CodeBase.EndsWith (this.assembly_file)) { return; } #endif sh.WriteLine("struct {0} {{", MapUtils.GetManagedType(t)); FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int max_type_len = 0, max_name_len = 0, max_native_len = 0; Array.ForEach(fields, delegate(FieldInfo f) { max_type_len = Math.Max(max_type_len, HeaderFileGenerator.GetType(f.FieldType).Length); max_name_len = Math.Max(max_name_len, GetNativeMemberName(f).Length); string native_type = MapUtils.GetNativeType(f); if (native_type != null) max_native_len = Math.Max(max_native_len, native_type.Length); }); SortFieldsInOffsetOrder(t, fields); foreach (FieldInfo field in fields) { string fname = GetNativeMemberName(field); sh.Write("\t{0,-" + max_type_len + "} {1};", GetType(field.FieldType), fname); string native_type = MapUtils.GetNativeType(field); if (native_type != null) { sh.Write(new string(' ', max_name_len - fname.Length)); sh.Write(" /* {0,-" + max_native_len + "} */", native_type); } sh.WriteLine(); } sh.WriteLine("};"); MapAttribute map = MapUtils.GetMapAttribute(t); if (map != null && map.NativeType != null && map.NativeType.Length != 0 && t.Assembly.CodeBase.EndsWith(this.assembly_file)) { sh.WriteLine(); sh.WriteLine( "int\n{0}_From{1} ({3}{4} from, {2} *to);\n" + "int\n{0}_To{1} ({2} *from, {3}{4} to);\n", MapUtils.GetNamespace(t), t.Name, map.NativeType, MapUtils.GetNativeType(t), t.IsValueType ? "*" : ""); Configuration.NativeExcludeSymbols.Add( string.Format("{0}_From{1}", MapUtils.GetNamespace(t), t.Name)); Configuration.NativeExcludeSymbols.Add( string.Format("{0}_To{1}", MapUtils.GetNamespace(t), t.Name)); Configuration.NativeExcludeSymbols.Sort(); } sh.WriteLine(); } private static string GetType(Type t) { if (typeof(Delegate).IsAssignableFrom(t)) return t.Name; return MapUtils.GetNativeType(t); } private void WriteMethodDeclaration(MethodInfo method, string entryPoint) { if (method.ReturnType.IsClass) { Console.WriteLine("warning: {0} has a return type of {1}, which is a reference type", entryPoint, method.ReturnType.FullName); } sh.Write(MapUtils.GetFunctionDeclaration(entryPoint, method)); sh.WriteLine(";"); } private void DumpTypeInfo(Type t) { if (t == null) return; sh.WriteLine("\t\t/* Type Info for " + t.FullName + ":"); foreach (MemberInfo mi in typeof(Type).GetMembers()) { sh.WriteLine("\t\t\t{0}={1}", mi.Name, GetMemberValue(mi, t)); } sh.WriteLine("\t\t */"); } private static string GetMemberValue(MemberInfo mi, Type t) { try { switch (mi.MemberType) { case MemberTypes.Constructor: case MemberTypes.Method: { MethodBase b = (MethodBase) mi; if (b.GetParameters().Length == 0) return b.Invoke(t, new object[] { }).ToString(); return "<>"; } case MemberTypes.Field: return ((FieldInfo) mi).GetValue(t).ToString(); case MemberTypes.Property: { PropertyInfo pi = (PropertyInfo) mi; if (!pi.CanRead) return "<>"; return pi.GetValue(t, null).ToString(); } default: return "<>"; } } catch (Exception e) { return "<>"; } } } class SourceFileGenerator : FileGenerator { StreamWriter sc; string file_prefix; public override void CreateFile(string assembly_name, string file_prefix) { sc = File.CreateText(file_prefix + ".c"); WriteHeader(sc, assembly_name); if (file_prefix.IndexOf("/") != -1) file_prefix = file_prefix.Substring(file_prefix.IndexOf("/") + 1); this.file_prefix = file_prefix; sc.WriteLine("#include "); sc.WriteLine("#include "); sc.WriteLine(); } public override void WriteAssemblyAttributes(Assembly assembly) { sc.WriteLine("/*\n * Implementation Macros\n */"); foreach (string def in Configuration.ImplementationMacros) { WriteMacroDefinition(sc, def); } sc.WriteLine(); sc.WriteLine("/*\n * Implementation Includes\n */"); foreach (string inc in Configuration.ImplementationHeaders) { WriteIncludeDeclaration(sc, inc); } sc.WriteLine(); sc.WriteLine("#include \"{0}.h\"", file_prefix); sc.WriteLine(@" #include /* errno, EOVERFLOW */ #include /* g* types, g_assert_not_reached() */"); WriteFallbackMacro("CNM_MININT8", "G_MININT8", sbyte.MinValue.ToString()); WriteFallbackMacro("CNM_MAXINT8", "G_MAXINT8", sbyte.MaxValue.ToString()); WriteFallbackMacro("CNM_MAXUINT8", "G_MAXUINT8", byte.MaxValue.ToString()); WriteFallbackMacro("CNM_MININT16", "G_MININT16", short.MinValue.ToString()); WriteFallbackMacro("CNM_MAXINT16", "G_MAXINT16", short.MaxValue.ToString()); WriteFallbackMacro("CNM_MAXUINT16", "G_MAXUINT16", ushort.MaxValue.ToString()); WriteFallbackMacro("CNM_MININT32", "G_MININT32", int.MinValue.ToString()); WriteFallbackMacro("CNM_MAXINT32", "G_MAXINT32", int.MaxValue.ToString()); WriteFallbackMacro("CNM_MAXUINT32", "G_MAXUINT32", uint.MaxValue.ToString() + "U"); WriteFallbackMacro("CNM_MININT64", "G_MININT64", long.MinValue.ToString() + "LL"); WriteFallbackMacro("CNM_MAXINT64", "G_MAXINT64", long.MaxValue.ToString() + "LL"); WriteFallbackMacro("CNM_MAXUINT64", "G_MAXUINT64", ulong.MaxValue.ToString() + "ULL"); sc.WriteLine(@" /* returns TRUE if @type is an unsigned type */ #define _cnm_integral_type_is_unsigned(type) \ (sizeof(type) == sizeof(gint8) \ ? (((type)-1) > CNM_MAXINT8) \ : sizeof(type) == sizeof(gint16) \ ? (((type)-1) > CNM_MAXINT16) \ : sizeof(type) == sizeof(gint32) \ ? (((type)-1) > CNM_MAXINT32) \ : sizeof(type) == sizeof(gint64) \ ? (((type)-1) > CNM_MAXINT64) \ : (g_assert_not_reached (), 0)) /* returns the minimum value of @type as a gint64 */ #define _cnm_integral_type_min(type) \ (_cnm_integral_type_is_unsigned (type) \ ? 0 \ : sizeof(type) == sizeof(gint8) \ ? CNM_MININT8 \ : sizeof(type) == sizeof(gint16) \ ? CNM_MININT16 \ : sizeof(type) == sizeof(gint32) \ ? CNM_MININT32 \ : sizeof(type) == sizeof(gint64) \ ? CNM_MININT64 \ : (g_assert_not_reached (), 0)) /* returns the maximum value of @type as a guint64 */ #define _cnm_integral_type_max(type) \ (_cnm_integral_type_is_unsigned (type) \ ? sizeof(type) == sizeof(gint8) \ ? CNM_MAXUINT8 \ : sizeof(type) == sizeof(gint16) \ ? CNM_MAXUINT16 \ : sizeof(type) == sizeof(gint32) \ ? CNM_MAXUINT32 \ : sizeof(type) == sizeof(gint64) \ ? CNM_MAXUINT64 \ : (g_assert_not_reached (), 0) \ : sizeof(type) == sizeof(gint8) \ ? CNM_MAXINT8 \ : sizeof(type) == sizeof(gint16) \ ? CNM_MAXINT16 \ : sizeof(type) == sizeof(gint32) \ ? CNM_MAXINT32 \ : sizeof(type) == sizeof(gint64) \ ? CNM_MAXINT64 \ : (g_assert_not_reached (), 0)) #ifdef _CNM_DUMP #define _cnm_dump(to_t,from) \ printf (""# %s -> %s: uns=%i; min=%llx; max=%llx; value=%llx; lt=%i; l0=%i; gt=%i; e=%i\n"", \ #from, #to_t, \ (int) _cnm_integral_type_is_unsigned (to_t), \ (gint64) (_cnm_integral_type_min (to_t)), \ (gint64) (_cnm_integral_type_max (to_t)), \ (gint64) (from), \ (((gint64) _cnm_integral_type_min (to_t)) <= (gint64) from), \ (from < 0), \ (((guint64) from) <= (guint64) _cnm_integral_type_max (to_t)), \ !((int) _cnm_integral_type_is_unsigned (to_t) \ ? ((0 <= from) && \ ((guint64) from <= (guint64) _cnm_integral_type_max (to_t))) \ : ((gint64) _cnm_integral_type_min(to_t) <= (gint64) from && \ (guint64) from <= (guint64) _cnm_integral_type_max (to_t))) \ ) #else /* ndef _CNM_DUMP */ #define _cnm_dump(to_t, from) do {} while (0) #endif /* def _CNM_DUMP */ #ifdef DEBUG #define _cnm_return_val_if_overflow(to_t,from,val) G_STMT_START { \ int uns = _cnm_integral_type_is_unsigned (to_t); \ gint64 min = (gint64) _cnm_integral_type_min (to_t); \ guint64 max = (guint64) _cnm_integral_type_max (to_t); \ gint64 sf = (gint64) from; \ guint64 uf = (guint64) from; \ if (!(uns ? ((0 <= from) && (uf <= max)) \ : (min <= sf && (from < 0 || uf <= max)))) { \ _cnm_dump(to_t, from); \ errno = EOVERFLOW; \ return (val); \ } \ } G_STMT_END #else /* !def DEBUG */ /* don't do any overflow checking */ #define _cnm_return_val_if_overflow(to_t,from,val) G_STMT_START { \ } G_STMT_END #endif /* def DEBUG */ "); } private void WriteFallbackMacro(string target, string glib, string def) { sc.WriteLine(@" #if defined ({1}) #define {0} {1} #else #define {0} ({2}) #endif", target, glib, def); } public override void WriteType(Type t, string ns, string fn) { if (!CanMapType(t)) return; string etype = MapUtils.GetNativeType(t); if (t.IsEnum) { bool bits = IsFlagsEnum(t); WriteFromManagedEnum(t, ns, fn, etype, bits); WriteToManagedEnum(t, ns, fn, etype, bits); } else { WriteFromManagedClass(t, ns, fn, etype); WriteToManagedClass(t, ns, fn, etype); } } private void WriteFromManagedEnum(Type t, string ns, string fn, string etype, bool bits) { sc.WriteLine("int {1}_From{2} ({0} x, {0} *r)", etype, ns, t.Name); sc.WriteLine("{"); sc.WriteLine("\t*r = 0;"); FieldInfo[] fields = t.GetFields(); Array.Sort(fields, MapUtils.MemberNameComparer); Array values = Enum.GetValues(t); foreach (FieldInfo fi in fields) { if (!fi.IsLiteral) continue; if (MapUtils.GetCustomAttribute(fi) != null) { sc.WriteLine("\t/* {0}_{1} is obsolete or optional; ignoring */", fn, fi.Name); continue; } MapAttribute map = MapUtils.GetMapAttribute(fi); bool is_bits = bits && (map != null ? map.SuppressFlags == null : true); if (is_bits) // properly handle case where [Flags] enumeration has helper // synonyms. e.g. DEFFILEMODE and ACCESSPERMS for mode_t. sc.WriteLine("\tif ((x & {0}_{1}) == {0}_{1})", fn, fi.Name); else if (GetSuppressFlags(map) == null) sc.WriteLine("\tif (x == {0}_{1})", fn, fi.Name); else sc.WriteLine("\tif ((x & {0}_{1}) == {0}_{2})", fn, map.SuppressFlags, fi.Name); sc.WriteLine("#ifdef {0}", fi.Name); if (is_bits || GetSuppressFlags(map) != null) sc.WriteLine("\t\t*r |= {1};", fn, fi.Name); else sc.WriteLine("\t\t{{*r = {1}; return 0;}}", fn, fi.Name); sc.WriteLine("#else /* def {0} */", fi.Name); if (is_bits && IsRedundant(t, fi, values)) { sc.WriteLine("\t\t{{/* Ignoring {0}_{1}, as it is constructed from other values */}}", fn, fi.Name); } else { sc.WriteLine("\t\t{errno = EINVAL; return -1;}"); } sc.WriteLine("#endif /* ndef {0} */", fi.Name); } // For many values, 0 is a valid value, but doesn't have it's own symbol. // Examples: Error (0 means "no error"), WaitOptions (0 means "no options"). // Make 0 valid for all conversions. sc.WriteLine("\tif (x == 0)\n\t\treturn 0;"); if (bits) sc.WriteLine("\treturn 0;"); else sc.WriteLine("\terrno = EINVAL; return -1;"); // return error if not matched sc.WriteLine("}\n"); } private static string GetSuppressFlags(MapAttribute map) { if (map != null) { return map.SuppressFlags == null ? null : map.SuppressFlags.Length == 0 ? null : map.SuppressFlags; } return null; } private static bool IsRedundant(Type t, FieldInfo fi, Array values) { long v = Convert.ToInt64(fi.GetValue(null)); long d = v; if (v == 0) return false; foreach (object o in values) { long e = Convert.ToInt64(o); if (((d & e) != 0) && (e < d)) { v &= ~e; } } if (v == 0) { return true; } return false; } private void WriteToManagedEnum(Type t, string ns, string fn, string etype, bool bits) { sc.WriteLine("int {1}_To{2} ({0} x, {0} *r)", etype, ns, t.Name); sc.WriteLine("{"); sc.WriteLine("\t*r = 0;", etype); // For many values, 0 is a valid value, but doesn't have it's own symbol. // Examples: Error (0 means "no error"), WaitOptions (0 means "no options"). // Make 0 valid for all conversions. sc.WriteLine("\tif (x == 0)\n\t\treturn 0;"); FieldInfo[] fields = t.GetFields(); Array.Sort(fields, MapUtils.MemberNameComparer); foreach (FieldInfo fi in fields) { if (!fi.IsLiteral) continue; MapAttribute map = MapUtils.GetMapAttribute(fi); bool is_bits = bits && (map != null ? map.SuppressFlags == null : true); sc.WriteLine("#ifdef {0}", fi.Name); if (is_bits) // properly handle case where [Flags] enumeration has helper // synonyms. e.g. DEFFILEMODE and ACCESSPERMS for mode_t. sc.WriteLine("\tif ((x & {1}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name); else if (GetSuppressFlags(map) == null) sc.WriteLine("\tif (x == {1})\n\t\t{{*r = {0}_{1}; return 0;}}", fn, fi.Name); else sc.WriteLine("\tif ((x & {2}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name, map.SuppressFlags); sc.WriteLine("#endif /* ndef {0} */", fi.Name); } if (bits) sc.WriteLine("\treturn 0;"); else sc.WriteLine("\terrno = EINVAL; return -1;"); sc.WriteLine("}\n"); } private void WriteFromManagedClass(Type t, string ns, string fn, string etype) { MapAttribute map = MapUtils.GetMapAttribute(t); if (map == null || map.NativeType == null || map.NativeType.Length == 0) return; string nativeMacro = GetAutoconfDefine(map.NativeType); sc.WriteLine("#ifdef {0}", nativeMacro); sc.WriteLine("int\n{0}_From{1} (struct {0}_{1} *from, {2} *to)", MapUtils.GetNamespace(t), t.Name, map.NativeType); WriteManagedClassConversion(t, delegate(FieldInfo field) { MapAttribute ft = MapUtils.GetMapAttribute(field); if (ft != null) return ft.NativeType; return MapUtils.GetNativeType(field.FieldType); }, delegate(FieldInfo field) { return GetNativeMemberName(field); }, delegate(FieldInfo field) { return field.Name; }, delegate(FieldInfo field) { return string.Format("{0}_From{1}", MapUtils.GetNamespace(field.FieldType), field.FieldType.Name); } ); sc.WriteLine("#endif /* ndef {0} */\n\n", nativeMacro); } private static string GetAutoconfDefine(string nativeType) { return string.Format("HAVE_{0}", nativeType.ToUpperInvariant().Replace(" ", "_")); } private delegate string GetFromType(FieldInfo field); private delegate string GetToFieldName(FieldInfo field); private delegate string GetFromFieldName(FieldInfo field); private delegate string GetFieldCopyMethod(FieldInfo field); private void WriteManagedClassConversion(Type t, GetFromType gft, GetFromFieldName gffn, GetToFieldName gtfn, GetFieldCopyMethod gfc) { MapAttribute map = MapUtils.GetMapAttribute(t); sc.WriteLine("{"); FieldInfo[] fields = GetFieldsToCopy(t); SortFieldsInOffsetOrder(t, fields); int max_len = 0; foreach (FieldInfo f in fields) { max_len = Math.Max(max_len, f.Name.Length); if (!MapUtils.IsIntegralType(f.FieldType)) continue; string d = GetAutoconfDefine(map, f); if (d != null) sc.WriteLine("#ifdef " + d); sc.WriteLine("\t_cnm_return_val_if_overflow ({0}, from->{1}, -1);", gft(f), gffn(f)); if (d != null) sc.WriteLine("#endif /* ndef " + d + " */"); } sc.WriteLine("\n\tmemset (to, 0, sizeof(*to));\n"); foreach (FieldInfo f in fields) { string d = GetAutoconfDefine(map, f); if (d != null) sc.WriteLine("#ifdef " + d); if (MapUtils.IsBlittableType(f.FieldType)) { sc.WriteLine("\tto->{0,-" + max_len + "} = from->{1};", gtfn(f), gffn(f)); } else if (f.FieldType.IsEnum) { sc.WriteLine("\tif ({0} (from->{1}, &to->{2}) != 0) {{", gfc(f), gffn(f), gtfn(f)); sc.WriteLine("\t\treturn -1;"); sc.WriteLine("\t}"); } else if (f.FieldType.IsValueType) { sc.WriteLine("\tif ({0} (&from->{1}, &to->{2}) != 0) {{", gfc(f), gffn(f), gtfn(f)); sc.WriteLine("\t\treturn -1;"); sc.WriteLine("\t}"); } if (d != null) sc.WriteLine("#endif /* ndef " + d + " */"); } sc.WriteLine(); sc.WriteLine("\treturn 0;"); sc.WriteLine("}"); } private void WriteToManagedClass(Type t, string ns, string fn, string etype) { MapAttribute map = MapUtils.GetMapAttribute(t); if (map == null || map.NativeType == null || map.NativeType.Length == 0) return; string nativeMacro = GetAutoconfDefine(map.NativeType); sc.WriteLine("#ifdef {0}", nativeMacro); sc.WriteLine("int\n{0}_To{1} ({2} *from, struct {0}_{1} *to)", MapUtils.GetNamespace(t), t.Name, map.NativeType); WriteManagedClassConversion(t, delegate(FieldInfo field) { return MapUtils.GetNativeType(field.FieldType); }, delegate(FieldInfo field) { return field.Name; }, delegate(FieldInfo field) { return GetNativeMemberName(field); }, delegate(FieldInfo field) { return string.Format("{0}_To{1}", MapUtils.GetNamespace(field.FieldType), field.FieldType.Name); } ); sc.WriteLine("#endif /* ndef {0} */\n\n", nativeMacro); } private static FieldInfo[] GetFieldsToCopy(Type t) { FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int count = 0; for (int i = 0; i < fields.Length; ++i) if (MapUtils.GetCustomAttribute(fields[i]) == null) ++count; FieldInfo[] rf = new FieldInfo [count]; for (int i = 0, j = 0; i < fields.Length; ++i) { if (MapUtils.GetCustomAttribute(fields[i]) == null) rf[j++] = fields[i]; } return rf; } private string GetAutoconfDefine(MapAttribute typeMap, FieldInfo field) { if (Configuration.AutoconfMembers.BinarySearch(field.Name) < 0 && Configuration.AutoconfMembers.BinarySearch(field.DeclaringType.Name + "." + field.Name) < 0) return null; return string.Format("HAVE_{0}_{1}", typeMap.NativeType.ToUpperInvariant().Replace(" ", "_"), field.Name.ToUpperInvariant()); } public override void CloseFile(string file_prefix) { sc.Close(); } } class ConvertFileGenerator : FileGenerator { StreamWriter scs; public override void CreateFile(string assembly_name, string file_prefix) { scs = File.CreateText(file_prefix + ".cs"); WriteHeader(scs, assembly_name, true); scs.WriteLine("using System;"); scs.WriteLine("using System.Runtime.InteropServices;"); scs.WriteLine("using Mono.Unix.Native;\n"); scs.WriteLine("namespace Mono.Unix.Native {\n"); scs.WriteLine("\tpublic sealed /* static */ partial class NativeConvert"); scs.WriteLine("\t{"); scs.WriteLine("\t\tprivate NativeConvert () {}\n"); scs.WriteLine("\t\tprivate const string LIB = \"{0}\";\n", Configuration.NativeLibraries[0]); scs.WriteLine("\t\tprivate static void ThrowArgumentException (object value)"); scs.WriteLine("\t\t{"); scs.WriteLine("\t\t\tthrow new ArgumentOutOfRangeException (\"value\", value,"); scs.WriteLine("\t\t\t\tLocale.GetText (\"Current platform doesn't support this value.\"));"); scs.WriteLine("\t\t}\n"); } public override void WriteType(Type t, string ns, string fn) { if (!CanMapType(t)) return; if (t.IsEnum) WriteEnum(t, ns, fn); else WriteStruct(t, ns, fn); } private void WriteEnum(Type t, string ns, string fn) { string mtype = Enum.GetUnderlyingType(t).Name; ObsoleteAttribute oa = MapUtils.GetCustomAttribute(t); string obsolete = ""; if (oa != null) { obsolete = string.Format("[Obsolete (\"{0}\", {1})]\n\t\t", oa.Message, oa.IsError ? "true" : "false"); } scs.WriteLine( "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_From{2}\")]\n" + "\t\tprivate static extern int From{2} ({2} value, out {3} rval);\n" + "\n" + "\t\t{0}public static bool TryFrom{2} ({2} value, out {3} rval)\n" + "\t\t{{\n" + "\t\t\treturn From{2} (value, out rval) == 0;\n" + "\t\t}}\n" + "\n" + "\t\t{0}public static {3} From{2} ({2} value)\n" + "\t\t{{\n" + "\t\t\t{3} rval;\n" + "\t\t\tif (From{2} (value, out rval) == -1)\n" + "\t\t\t\tThrowArgumentException (value);\n" + "\t\t\treturn rval;\n" + "\t\t}}\n" + "\n" + "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_To{2}\")]\n" + "\t\tprivate static extern int To{2} ({3} value, out {2} rval);\n" + "\n" + "\t\t{0}public static bool TryTo{2} ({3} value, out {2} rval)\n" + "\t\t{{\n" + "\t\t\treturn To{2} (value, out rval) == 0;\n" + "\t\t}}\n" + "\n" + "\t\t{0}public static {2} To{2} ({3} value)\n" + "\t\t{{\n" + "\t\t\t{2} rval;\n" + "\t\t\tif (To{2} (value, out rval) == -1)\n" + "\t\t\t\tThrowArgumentException (value);\n" + "\t\t\treturn rval;\n" + "\t\t}}\n", obsolete, ns, t.Name, mtype ); } private void WriteStruct(Type t, string ns, string fn) { if (MapUtils.IsDelegate(t)) return; MapAttribute map = MapUtils.GetMapAttribute(t); if (map == null || map.NativeType == null || map.NativeType.Length == 0) return; ObsoleteAttribute oa = MapUtils.GetCustomAttribute(t); string obsolete = ""; if (oa != null) { obsolete = string.Format("[Obsolete (\"{0}\", {1})]\n\t\t", oa.Message, oa.IsError ? "true" : "false"); } string _ref = t.IsValueType ? "ref " : ""; string _out = t.IsValueType ? "out " : ""; scs.WriteLine( "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_From{2}\")]\n" + "\t\tprivate static extern int From{2} ({3}{2} source, IntPtr destination);\n" + "\n" + "\t\t{0}public static bool TryCopy ({3}{2} source, IntPtr destination)\n" + "\t\t{{\n" + "\t\t\treturn From{2} ({3}source, destination) == 0;\n" + "\t\t}}\n" + "\n" + "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_To{2}\")]\n" + "\t\tprivate static extern int To{2} (IntPtr source, {4}{2} destination);\n" + "\n" + "\t\t{0}public static bool TryCopy (IntPtr source, {4}{2} destination)\n" + "\t\t{{\n" + "\t\t\treturn To{2} (source, {4}destination) == 0;\n" + "\t\t}}\n", obsolete, ns, t.Name, _ref, _out ); } public override void CloseFile(string file_prefix) { scs.WriteLine("\t}"); scs.WriteLine("}\n"); scs.Close(); } } class ConvertDocFileGenerator : FileGenerator { StreamWriter scs; public override void CreateFile(string assembly_name, string file_prefix) { scs = File.CreateText(file_prefix + ".xml"); scs.WriteLine(" "); } public override void WriteType(Type t, string ns, string fn) { if (!CanMapType(t) || !t.IsEnum) return; bool bits = IsFlagsEnum(t); string type = GetCSharpType(t); string mtype = Enum.GetUnderlyingType(t).FullName; string member = t.Name; string ftype = t.FullName; string to_returns = ""; string to_remarks = ""; string to_exception = ""; if (bits) { to_returns = "An approximation of the equivalent managed value."; to_remarks = @"The current conversion functions are unable to determine if a value in a [Flags]-marked enumeration does not exist on the current platform. As such, if contains a flag value which the current platform doesn't support, it will not be present in the managed value returned. This should only be a problem if was not previously returned by .\n"; } else { to_returns = "The equivalent managed value."; to_exception = @" has no equivalent managed value. "; } scs.WriteLine(@" Method System.Boolean The managed value to convert. The OS-specific equivalent value. Converts a enumeration value to an OS-specific value. if the conversion was successful; otherwise, . This is an exception-safe alternative to . If successful, this method stores the OS-specific equivalent value of into . Otherwise, will contain 0. Method {3} The managed value to convert. Converts a to an OS-specific value. The equivalent OS-specific value. has no equivalent OS-specific value. Method System.Boolean The OS-specific value to convert. The managed equivalent value Converts an OS-specific value to a . if the conversion was successful; otherwise, . This is an exception-safe alternative to . If successful, this method stores the managed equivalent value of into . Otherwise, will contain a 0 cast to a . " + to_remarks + @" Method {0} The OS-specific value to convert. Converts an OS-specific value to a . " + to_returns + "\n" + to_exception + @" " + to_remarks + @" ", ftype, member, type, mtype ); } private string GetCSharpType(Type t) { string ut = t.Name; if (t.IsEnum) ut = Enum.GetUnderlyingType(t).Name; Type et = t.GetElementType(); if (et != null && et.IsEnum) ut = Enum.GetUnderlyingType(et).Name; string type = null; switch (ut) { case "Boolean": type = "bool"; break; case "Byte": type = "byte"; break; case "SByte": type = "sbyte"; break; case "Int16": type = "short"; break; case "UInt16": type = "ushort"; break; case "Int32": type = "int"; break; case "UInt32": type = "uint"; break; case "Int64": type = "long"; break; case "UInt64": type = "ulong"; break; } return type; } public override void CloseFile(string file_prefix) { scs.WriteLine(" "); scs.Close(); } } } // vim: noexpandtab