diff --git a/Source/Bind/CSharpSpecWriter.cs b/Source/Bind/CSharpSpecWriter.cs new file mode 100644 index 00000000..13b5a1ec --- /dev/null +++ b/Source/Bind/CSharpSpecWriter.cs @@ -0,0 +1,484 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using Bind.Structures; + +namespace Bind +{ + using Delegate = Bind.Structures.Delegate; + using Enum = Bind.Structures.Enum; + using Type = Bind.Structures.Type; + + sealed class CSharpSpecWriter : ISpecWriter + { + readonly string wrappersFile; + readonly string enumsFile; + readonly string delegatesFile; + readonly string importsFile; + readonly char[] numbers = "0123456789".ToCharArray(); + + public CSharpSpecWriter(string wrappersFile, string importsFile, string enumsFile, string delegatesFile) + { + this.wrappersFile = wrappersFile; + this.importsFile = importsFile; + this.enumsFile = enumsFile; + this.delegatesFile = delegatesFile; + } + + #region WriteBindings + + public void WriteBindings(DelegateCollection delegates, FunctionCollection wrappers, EnumCollection enums) + { + Console.WriteLine("Writing bindings to {0}", Settings.OutputPath); + if (!Directory.Exists(Settings.OutputPath)) + Directory.CreateDirectory(Settings.OutputPath); + + string temp_enums_file = Path.GetTempFileName(); + string temp_delegates_file = Path.GetTempFileName(); + string temp_core_file = Path.GetTempFileName(); + string temp_wrappers_file = Path.GetTempFileName(); + + // Enums + using (BindStreamWriter sw = new BindStreamWriter(temp_enums_file)) + { + WriteLicense(sw); + + sw.WriteLine("using System;"); + sw.WriteLine(); + + if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None) + { + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + sw.Indent(); + sw.WriteLine("static partial class {0}", Settings.OutputClass); + } + else + sw.WriteLine("namespace {0}", Settings.EnumsOutput); + + sw.WriteLine("{"); + + sw.Indent(); + WriteEnums(sw, enums); + sw.Unindent(); + + if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None) + { + sw.WriteLine("}"); + sw.Unindent(); + } + + sw.WriteLine("}"); + } + + // Delegates + using (BindStreamWriter sw = new BindStreamWriter(temp_delegates_file)) + { + WriteLicense(sw); + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + sw.Indent(); + + sw.WriteLine("using System;"); + sw.WriteLine("using System.Text;"); + sw.WriteLine("using System.Runtime.InteropServices;"); + + sw.WriteLine("#pragma warning disable 0649"); + WriteDelegates(sw, delegates); + + sw.Unindent(); + sw.WriteLine("}"); + } + + // Core + using (BindStreamWriter sw = new BindStreamWriter(temp_core_file)) + { + WriteLicense(sw); + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + sw.Indent(); + //specWriter.WriteTypes(sw, Bind.Structures.Type.CSTypes); + sw.WriteLine("using System;"); + sw.WriteLine("using System.Text;"); + sw.WriteLine("using System.Runtime.InteropServices;"); + + WriteImports(sw, delegates); + + sw.Unindent(); + sw.WriteLine("}"); + } + + // Wrappers + using (BindStreamWriter sw = new BindStreamWriter(temp_wrappers_file)) + { + WriteLicense(sw); + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + sw.Indent(); + + sw.WriteLine("using System;"); + sw.WriteLine("using System.Text;"); + sw.WriteLine("using System.Runtime.InteropServices;"); + + WriteWrappers(sw, wrappers, Type.CSTypes); + + sw.Unindent(); + sw.WriteLine("}"); + } + + string output_enums = Path.Combine(Settings.OutputPath, enumsFile); + string output_delegates = Path.Combine(Settings.OutputPath, delegatesFile); + string output_core = Path.Combine(Settings.OutputPath, importsFile); + string output_wrappers = Path.Combine(Settings.OutputPath, wrappersFile); + + if (File.Exists(output_enums)) File.Delete(output_enums); + if (File.Exists(output_delegates)) File.Delete(output_delegates); + if (File.Exists(output_core)) File.Delete(output_core); + if (File.Exists(output_wrappers)) File.Delete(output_wrappers); + + File.Move(temp_enums_file, output_enums); + File.Move(temp_delegates_file, output_delegates); + File.Move(temp_core_file, output_core); + File.Move(temp_wrappers_file, output_wrappers); + } + + #endregion + + #region WriteDelegates + + public void WriteDelegates(BindStreamWriter sw, DelegateCollection delegates) + { + Trace.WriteLine(String.Format("Writing delegates to:\t{0}.{1}.{2}", Settings.OutputNamespace, Settings.OutputClass, Settings.DelegatesClass)); + + sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute + sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments + + sw.WriteLine(); + sw.WriteLine("partial class {0}", Settings.OutputClass); + sw.WriteLine("{"); + sw.Indent(); + + sw.WriteLine("internal static partial class {0}", Settings.DelegatesClass); + sw.WriteLine("{"); + sw.Indent(); + + foreach (Delegate d in delegates.Values) + { + sw.WriteLine("[System.Security.SuppressUnmanagedCodeSecurity()]"); + sw.WriteLine("internal {0};", d.ToString()); + sw.WriteLine("internal {0}static {1} {2}{1};", // = null + d.Unsafe ? "unsafe " : "", + d.Name, + Settings.FunctionPrefix); + } + + sw.Unindent(); + sw.WriteLine("}"); + + sw.Unindent(); + sw.WriteLine("}"); + } + + #endregion + + #region WriteImports + + public void WriteImports(BindStreamWriter sw, DelegateCollection delegates) + { + Trace.WriteLine(String.Format("Writing imports to:\t{0}.{1}.{2}", Settings.OutputNamespace, Settings.OutputClass, Settings.ImportsClass)); + + sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute + sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments + + sw.WriteLine(); + sw.WriteLine("partial class {0}", Settings.OutputClass); + sw.WriteLine("{"); + sw.Indent(); + sw.WriteLine(); + sw.WriteLine("internal static partial class {0}", Settings.ImportsClass); + sw.WriteLine("{"); + sw.Indent(); + //sw.WriteLine("static {0}() {1} {2}", Settings.ImportsClass, "{", "}"); // Disable BeforeFieldInit + sw.WriteLine(); + foreach (Delegate d in delegates.Values) + { + sw.WriteLine("[System.Security.SuppressUnmanagedCodeSecurity()]"); + sw.WriteLine( + "[System.Runtime.InteropServices.DllImport({0}.Library, EntryPoint = \"{1}{2}\"{3})]", + Settings.OutputClass, + Settings.FunctionPrefix, + d.Name, + d.Name.EndsWith("W") || d.Name.EndsWith("A") ? ", CharSet = CharSet.Auto" : ", ExactSpelling = true" + ); + sw.WriteLine("internal extern static {0};", d.DeclarationString()); + } + sw.Unindent(); + sw.WriteLine("}"); + sw.Unindent(); + sw.WriteLine("}"); + } + + #endregion + + #region WriteWrappers + + public void WriteWrappers(BindStreamWriter sw, FunctionCollection wrappers, Dictionary CSTypes) + { + Trace.WriteLine(String.Format("Writing wrappers to:\t{0}.{1}", Settings.OutputNamespace, Settings.OutputClass)); + + sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute + sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments + sw.WriteLine("#pragma warning disable 1572"); // Wrong param comments + sw.WriteLine("#pragma warning disable 1573"); // Missing param comments + + sw.WriteLine(); + sw.WriteLine("partial class {0}", Settings.OutputClass); + sw.WriteLine("{"); + + sw.Indent(); + //sw.WriteLine("static {0}() {1} {2}", className, "{", "}"); // Static init in GLHelper.cs + sw.WriteLine(); + + int current = 0; + foreach (string key in wrappers.Keys) + { + if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core") + { + if (!Char.IsDigit(key[0])) + { + sw.WriteLine("public static partial class {0}", key); + } + else + { + // Identifiers cannot start with a number: + sw.WriteLine("public static partial class {0}{1}", Settings.ConstantPrefix, key); + } + sw.WriteLine("{"); + sw.Indent(); + } + + wrappers[key].Sort(); + foreach (Function f in wrappers[key]) + { + current = WriteWrapper(sw, current, f); + } + + if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core") + { + sw.Unindent(); + sw.WriteLine("}"); + sw.WriteLine(); + } + } + sw.Unindent(); + sw.WriteLine("}"); + } + + int WriteWrapper(BindStreamWriter sw, int current, Function f) + { + if ((Settings.Compatibility & Settings.Legacy.NoDocumentation) == 0) + { + Console.WriteLine("Creating docs for #{0} ({1})", current++, f.Name); + WriteDocumentation(sw, f); + } + WriteMethod(sw, f); + return current; + } + + private static void WriteMethod(BindStreamWriter sw, Function f) + { + if (f.Deprecated && Settings.IsEnabled(Settings.Legacy.AddDeprecationWarnings)) + { + sw.WriteLine("[Obsolete(\"Deprecated in OpenGL {0}\")]", f.DeprecatedVersion); + } + + if (!f.CLSCompliant) + { + sw.WriteLine("[System.CLSCompliant(false)]"); + } + + sw.WriteLine("[AutoGenerated(Category = \"{0}\", Version = \"{1}\", EntryPoint = \"{2}\")]", + f.Category, f.Version, Settings.FunctionPrefix + f.WrappedDelegate.Name); + sw.WriteLine("public static "); + sw.Write(f); + sw.WriteLine(); + } + + static DocProcessor processor = new DocProcessor(Path.Combine(Settings.DocPath, Settings.DocFile)); + static Dictionary docfiles; + void WriteDocumentation(BindStreamWriter sw, Function f) + { + if (docfiles == null) + { + docfiles = new Dictionary(); + foreach (string file in Directory.GetFiles(Settings.DocPath)) + { + docfiles.Add(Path.GetFileName(file), file); + } + } + + string docfile = null; + try + { + docfile = Settings.FunctionPrefix + f.WrappedDelegate.Name + ".xml"; + if (!docfiles.ContainsKey(docfile)) + docfile = Settings.FunctionPrefix + f.TrimmedName + ".xml"; + if (!docfiles.ContainsKey(docfile)) + docfile = Settings.FunctionPrefix + f.TrimmedName.TrimEnd(numbers) + ".xml"; + + string doc = null; + if (docfiles.ContainsKey(docfile)) + { + doc = processor.ProcessFile(docfiles[docfile]); + } + if (doc == null) + { + doc = "/// "; + } + + int summary_start = doc.IndexOf("") + "".Length; + string warning = "[deprecated: v{0}]"; + string category = "[requires: {0}]"; + if (f.Deprecated) + { + warning = String.Format(warning, f.DeprecatedVersion); + doc = doc.Insert(summary_start, warning); + } + + if (f.Extension != "Core" && !String.IsNullOrEmpty(f.Category)) + { + category = String.Format(category, f.Category); + doc = doc.Insert(summary_start, category); + } + else if (!String.IsNullOrEmpty(f.Version)) + { + if (f.Category.StartsWith("VERSION")) + category = String.Format(category, "v" + f.Version); + else + category = String.Format(category, "v" + f.Version + " and " + f.Category); + doc = doc.Insert(summary_start, category); + } + + sw.WriteLine(doc); + } + catch (Exception e) + { + Console.WriteLine("[Warning] Error processing file {0}: {1}", docfile, e.ToString()); + } + } + + #endregion + + #region WriteTypes + + public void WriteTypes(BindStreamWriter sw, Dictionary CSTypes) + { + sw.WriteLine(); + foreach (string s in CSTypes.Keys) + { + sw.WriteLine("using {0} = System.{1};", s, CSTypes[s]); + } + } + + #endregion + + #region WriteEnums + + public void WriteEnums(BindStreamWriter sw, EnumCollection enums) + { + //sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute + sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments + sw.WriteLine(); + + if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None) + Trace.WriteLine(String.Format("Writing enums to:\t{0}.{1}.{2}", Settings.OutputNamespace, Settings.OutputClass, Settings.NestedEnumsClass)); + else + Trace.WriteLine(String.Format("Writing enums to:\t{0}", Settings.EnumsOutput)); + + if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) == Settings.Legacy.None) + { + if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None && + !String.IsNullOrEmpty(Settings.NestedEnumsClass)) + { + sw.WriteLine("public class Enums"); + sw.WriteLine("{"); + sw.Indent(); + } + + foreach (Enum @enum in enums.Values) + { + sw.Write(@enum); + sw.WriteLine(); + } + + if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None && + !String.IsNullOrEmpty(Settings.NestedEnumsClass)) + { + sw.Unindent(); + sw.WriteLine("}"); + } + } + else + { + // Tao legacy mode: dump all enums as constants in GLClass. + foreach (Constant c in enums[Settings.CompleteEnumName].ConstantCollection.Values) + { + // Print constants avoiding circular definitions + if (c.Name != c.Value) + { + sw.WriteLine(String.Format( + "public const int {0} = {2}((int){1});", + c.Name.StartsWith(Settings.ConstantPrefix) ? c.Name : Settings.ConstantPrefix + c.Name, + Char.IsDigit(c.Value[0]) ? c.Value : c.Value.StartsWith(Settings.ConstantPrefix) ? c.Value : Settings.ConstantPrefix + c.Value, + c.Unchecked ? "unchecked" : "")); + } + else + { + } + } + } + } + + #endregion + + #region WriteLicense + + public void WriteLicense(BindStreamWriter sw) + { + sw.WriteLine(File.ReadAllText(Path.Combine(Settings.InputPath, Settings.LicenseFile))); + sw.WriteLine(); + } + + #endregion + } +} diff --git a/Source/Bind/ES/ESGenerator.cs b/Source/Bind/ES/ESGenerator.cs index ae4c602b..3a70e3b9 100644 --- a/Source/Bind/ES/ESGenerator.cs +++ b/Source/Bind/ES/ESGenerator.cs @@ -38,171 +38,5 @@ namespace Bind.ES Settings.OutputNamespace = "OpenTK.Graphics." + nsName; Settings.OutputPath = Path.Combine(Settings.OutputPath, dirName); } - - public override DelegateCollection ReadDelegates(StreamReader specFile) - { - DelegateCollection delegates = new DelegateCollection(); - XPathDocument specs = new XPathDocument(specFile); - XPathDocument overrides = new XPathDocument(new StreamReader(Path.Combine(Settings.InputPath, functionOverridesFile))); - - foreach (XPathNavigator nav in new XPathNavigator[] { - specs.CreateNavigator().SelectSingleNode("/signatures"), - overrides.CreateNavigator().SelectSingleNode("/overrides/add") }) - { - if (nav != null) - { - foreach (XPathNavigator node in nav.SelectChildren("function", String.Empty)) - { - var name = node.GetAttribute("name", String.Empty); - - // Check whether we are adding to an existing delegate or creating a new one. - Delegate d = null; - if (delegates.ContainsKey(name)) - { - d = delegates[name]; - } - else - { - d = new Delegate(); - d.Name = name; - d.Version = node.GetAttribute("version", String.Empty); - d.Category = node.GetAttribute("category", String.Empty); - d.DeprecatedVersion = node.GetAttribute("deprecated", String.Empty); - d.Deprecated = !String.IsNullOrEmpty(d.DeprecatedVersion); - } - - foreach (XPathNavigator param in node.SelectChildren(XPathNodeType.Element)) - { - switch (param.Name) - { - case "returns": - d.ReturnType.CurrentType = param.GetAttribute("type", String.Empty); - break; - - case "param": - Parameter p = new Parameter(); - p.CurrentType = param.GetAttribute("type", String.Empty); - p.Name = param.GetAttribute("name", String.Empty); - - string element_count = param.GetAttribute("elementcount", String.Empty); - if (String.IsNullOrEmpty(element_count)) - element_count = param.GetAttribute("count", String.Empty); - if (!String.IsNullOrEmpty(element_count)) - p.ElementCount = Int32.Parse(element_count); - - p.Flow = Parameter.GetFlowDirection(param.GetAttribute("flow", String.Empty)); - - d.Parameters.Add(p); - break; - } - } - - delegates.Add(d); - } - } - } - - return delegates; - } - - public override Dictionary ReadTypeMap(StreamReader specFile) - { - return base.ReadTypeMap(specFile); - } - - public override Dictionary ReadCSTypeMap(StreamReader specFile) - { - return base.ReadCSTypeMap(specFile); - } - - public override EnumCollection ReadEnums(StreamReader specFile) - { - // First, read all enum definitions from spec and override file. - // Afterwards, read all token/enum overrides from overrides file. - // Every single enum is merged into - - EnumCollection enums = new EnumCollection(); - Enum all = new Enum() { Name = Settings.CompleteEnumName }; - XPathDocument specs = new XPathDocument(specFile); - XPathDocument overrides = new XPathDocument(new StreamReader(Path.Combine(Settings.InputPath, functionOverridesFile))); - - foreach (XPathNavigator nav in new XPathNavigator[] { - specs.CreateNavigator().SelectSingleNode("/signatures"), - overrides.CreateNavigator().SelectSingleNode("/overrides/add") }) - { - if (nav != null) - { - foreach (XPathNavigator node in nav.SelectChildren("enum", String.Empty)) - { - Enum e = new Enum() - { - Name = node.GetAttribute("name", String.Empty), - Type = node.GetAttribute("type", String.Empty) - }; - if (String.IsNullOrEmpty(e.Name)) - throw new InvalidOperationException(String.Format("Empty name for enum element {0}", node.ToString())); - - foreach (XPathNavigator param in node.SelectChildren(XPathNodeType.Element)) - { - Constant c = null; - switch (param.Name) - { - case "token": - c = new Constant - { - Name = param.GetAttribute("name", String.Empty), - Value = param.GetAttribute("value", String.Empty) - }; - break; - - case "use": - c = new Constant - { - Name = param.GetAttribute("token", String.Empty), - Reference = param.GetAttribute("enum", String.Empty), - Value = param.GetAttribute("token", String.Empty), - }; - break; - - default: - throw new NotSupportedException(); - } - Utilities.Merge(all, c); - try - { - if (!e.ConstantCollection.ContainsKey(c.Name)) - { - e.ConstantCollection.Add(c.Name, c); - } - else if (e.ConstantCollection[c.Name].Value != c.Value) - { - var existing = e.ConstantCollection[c.Name]; - if (existing.Reference != null && c.Reference == null) - { - e.ConstantCollection[c.Name] = c; - } - else if (existing.Reference == null && c.Reference != null) - { } // Keep existing - else - { - Console.WriteLine("[Warning] Conflicting token {0}.{1} with value {2} != {3}", - e.Name, c.Name, e.ConstantCollection[c.Name].Value, c.Value); - } - } - } - catch (ArgumentException ex) - { - Console.WriteLine("[Warning] Failed to add constant {0} to enum {1}: {2}", c.Name, e.Name, ex.Message); - } - } - - Utilities.Merge(enums, e); - } - } - } - - Utilities.Merge(enums, all); - return enums; - } } } diff --git a/Source/Bind/GL2/GL4Generator.cs b/Source/Bind/GL2/GL4Generator.cs index defd5d2e..33cd7149 100644 --- a/Source/Bind/GL2/GL4Generator.cs +++ b/Source/Bind/GL2/GL4Generator.cs @@ -1,4 +1,31 @@ -using System; +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/Source/Bind/GL2/Generator.cs b/Source/Bind/GL2/Generator.cs index 56a75916..e23afb31 100644 --- a/Source/Bind/GL2/Generator.cs +++ b/Source/Bind/GL2/Generator.cs @@ -20,7 +20,7 @@ namespace Bind.GL2 { class Generator : IBind { - #region --- Fields --- + #region Fields protected static string glTypemap = "GL2/gl.tm"; protected static string csTypemap = "csharp.tm"; @@ -42,9 +42,14 @@ namespace Bind.GL2 protected static readonly char[] numbers = "0123456789".ToCharArray(); //protected static readonly Dictionary doc_replacements; + + protected ISpecReader SpecReader = new XmlSpecReader(functionOverridesFile); + protected ISpecWriter SpecWriter = new CSharpSpecWriter(wrappersFile, importsFile, + enumsFile, delegatesFile); + #endregion - #region --- Constructors --- + #region Constructors public Generator() { @@ -61,823 +66,30 @@ namespace Bind.GL2 #endregion - #region public void Process() + #region Process public virtual void Process() { - var overrides = new XPathDocument(Path.Combine(Settings.InputPath, functionOverridesFile)); + var overrides = new XPathDocument(Path.Combine(Settings.InputPath, functionOverridesFile)); - Type.Initialize(glTypemap, csTypemap); - var enums = ReadEnums(new StreamReader(Path.Combine(Settings.InputPath, enumSpec))); - var delegates = ReadDelegates(new StreamReader(Path.Combine(Settings.InputPath, glSpec))); + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, glTypemap)) + { + Type.GLTypes = SpecReader.ReadTypeMap(sr); + } + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, csTypemap)) + { + Type.CSTypes = SpecReader.ReadCSTypeMap(sr); + } + + var enums = SpecReader.ReadEnums(new StreamReader(Path.Combine(Settings.InputPath, enumSpec))); + var delegates = SpecReader.ReadDelegates(new StreamReader(Path.Combine(Settings.InputPath, glSpec))); enums = new EnumProcessor(overrides).Process(enums); var wrappers = new FuncProcessor(overrides).Process(delegates, enums); - WriteBindings(delegates, wrappers, enums); + SpecWriter.WriteBindings(delegates, wrappers, enums); } #endregion - - #region private void Translate() -#if false - protected virtual void Translate() - { - Bind.Structures.Enum.GLEnums.Translate(); - } -#endif - #endregion - - #region ISpecReader Members - - #region public virtual DelegateCollection ReadDelegates(StreamReader specFile) - - public virtual DelegateCollection ReadDelegates(StreamReader specFile) - { - Console.WriteLine("Reading function specs."); - - DelegateCollection delegates = new DelegateCollection(); - - XPathDocument function_overrides = new XPathDocument(Path.Combine(Settings.InputPath, functionOverridesFile)); - - do - { - string line = NextValidLine(specFile); - if (String.IsNullOrEmpty(line)) - break; - - while (line.Contains("(") && !specFile.EndOfStream) - { - // Get next OpenGL function - - Delegate d = new Delegate(); - - // Get function name: - d.Name = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries)[0]; - - do - { - // Get function parameters and return value - - line = specFile.ReadLine(); - List words = new List( - line.Replace('\t', ' ').Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries) - ); - - if (words.Count == 0) - break; - - // Identify line: - switch (words[0]) - { - case "return": // Line denotes return value - d.ReturnType.CurrentType = words[1]; - break; - - case "param": // Line denotes parameter - Parameter p = new Parameter(); - - p.Name = Utilities.Keywords.Contains(words[1]) ? "@" + words[1] : words[1]; - p.CurrentType = words[2]; - p.Pointer += words[4].Contains("array") ? 1 : 0; - p.Pointer += words[4].Contains("reference") ? 1 : 0; - if (p.Pointer != 0 && words.Count > 5 && words[5].Contains("[1]")) - p.ElementCount = 1; - p.Flow = words[3] == "in" ? FlowDirection.In : FlowDirection.Out; - - d.Parameters.Add(p); - break; - - // GetTexParameterIivEXT and GetTexParameterIuivEXT define two(!) versions (why?) - case "version": // Line denotes function version (i.e. 1.0, 1.2, 1.5) - d.Version = words[1]; - break; - - case "category": - d.Category = words[1]; - break; - - case "deprecated": - d.Deprecated = true; - d.DeprecatedVersion = words[1]; - break; - } - } - while (!specFile.EndOfStream); - - delegates.Add(d); - } - } - while (!specFile.EndOfStream); - - return delegates; - } - - #endregion - - #region public virtual EnumCollection ReadEnums(StreamReader specFile) - - public virtual EnumCollection ReadEnums(StreamReader specFile) - { - Trace.WriteLine("Reading opengl enumerant specs."); - Trace.Indent(); - - EnumCollection enums = new EnumCollection(); - - // complete_enum contains all opengl enumerants. - Enum complete_enum = new Enum(); - complete_enum.Name = Settings.CompleteEnumName; - - do - { - string line = NextValidLine(specFile); - if (String.IsNullOrEmpty(line)) - break; - - line = line.Replace('\t', ' '); - - // We just encountered the start of a new enumerant: - while (!String.IsNullOrEmpty(line) && line.Contains("enum")) - { - string[] words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries); - if (words.Length == 0) - continue; - - // Declare a new enumerant - Enum e = new Enum(); - e.Name = Char.IsDigit(words[0][0]) ? Settings.ConstantPrefix + words[0] : words[0]; - - // And fill in the values for this enumerant - do - { - line = NextValidLine(specFile); - - if (String.IsNullOrEmpty(line) || line.StartsWith("#")) - continue; - - if (line.Contains("enum:") || specFile.EndOfStream) - break; - - line = line.Replace('\t', ' '); - words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries); - - if (words.Length == 0) - continue; - - // If we reach this point, we have found a new value for the current enumerant - Constant c = new Constant(); - if (line.Contains("=")) - { - // Trim the name's prefix, but only if not in Tao compat mode. - if (Settings.Compatibility == Settings.Legacy.Tao) - { - } - else - { - if (words[0].StartsWith(Settings.ConstantPrefix)) - words[0] = words[0].Substring(Settings.ConstantPrefix.Length); - - if (Char.IsDigit(words[0][0])) - words[0] = Settings.ConstantPrefix + words[0]; - } - - c.Name = words[0]; - c.Value = words[2]; - } - else if (words[0] == "use") - { - // Trim the prefix. - if (words[2].StartsWith(Settings.ConstantPrefix)) - words[2] = words[2].Substring(Settings.ConstantPrefix.Length); - - // If the remaining string starts with a digit, we were wrong above. - // Re-add the "GL_" - if (Char.IsDigit(words[2][0])) - words[2] = Settings.ConstantPrefix + words[2]; - - c.Name = words[2]; - c.Reference = words[1]; - c.Value = words[2]; - } - else - { - // Typical cause is hand-editing the specs and forgetting to add an '=' sign. - throw new InvalidOperationException(String.Format( - "[Error] Invalid constant definition: \"{0}\"", line)); - } - - //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c)) - //SpecTranslator.Merge(e.Members, c); - if (!e.ConstantCollection.ContainsKey(c.Name)) - e.ConstantCollection.Add(c.Name, c); - else - Trace.WriteLine(String.Format( - "Spec error: Constant {0} defined twice in enum {1}, discarding last definition.", - c.Name, e.Name)); - - // Insert the current constant in the list of all constants. - //SpecTranslator.Merge(complete_enum.Members, c); - complete_enum = Utilities.Merge(complete_enum, c); - } - while (!specFile.EndOfStream); - - // At this point, the complete value list for the current enumerant has been read, so add this - // enumerant to the list. - //e.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "public enum " + e.Name)); - //e.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "public enum " + e.Name)); - - // (disabled) Hack - discard Boolean enum, it fsucks up the fragile translation code ahead. - //if (!e.Name.Contains("Bool")) - //Utilities.Merge(enums, e); - - //e.Translate(); - - if (!enums.ContainsKey(e.Name)) - enums.Add(e.Name, e); - else - { - // The enum already exists, merge constants. - foreach (Constant t in e.ConstantCollection.Values) - Utilities.Merge(enums[e.Name], t); - } - } - } - while (!specFile.EndOfStream); - - enums.Add(complete_enum.Name, complete_enum); - - Trace.Unindent(); - - return enums; - } - - #endregion - - #region public virtual Dictionary ReadTypeMap(StreamReader specFile) - - public virtual Dictionary ReadTypeMap(StreamReader specFile) - { - Console.WriteLine("Reading opengl types."); - Dictionary GLTypes = new Dictionary(); - - if (specFile == null) - return GLTypes; - - do - { - string line = specFile.ReadLine(); - - if (String.IsNullOrEmpty(line) || line.StartsWith("#")) - continue; - - string[] words = line.Split(" ,*\t".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - - if (words[0].ToLower() == "void") - { - // Special case for "void" -> "". We make it "void" -> "void" - GLTypes.Add(words[0], "void"); - } - else if (words[0] == "VoidPointer" || words[0] == "ConstVoidPointer") - { - // "(Const)VoidPointer" -> "void*" - GLTypes.Add(words[0], "void*"); - } - else if (words[0] == "CharPointer" || words[0] == "charPointerARB") - { - // The typematching logic cannot handle pointers to pointers, e.g. CharPointer* -> char** -> string* -> string[]. - // Hence we give it a push. - // Note: When both CurrentType == "String" and Pointer == true, the typematching is hardcoded to use - // String[] or StringBuilder[]. - GLTypes.Add(words[0], "String"); - } - /*else if (words[0].Contains("Pointer")) - { - GLTypes.Add(words[0], words[1].Replace("Pointer", "*")); - }*/ - else if (words[1].Contains("GLvoid")) - { - GLTypes.Add(words[0], "void"); - } - else if (words[1] == "const" && words[2] == "GLubyte") - { - GLTypes.Add(words[0], "String"); - } - else if (words[1] == "struct") - { - GLTypes.Add(words[0], words[2]); - } - else - { - GLTypes.Add(words[0], words[1]); - } - } - while (!specFile.EndOfStream); - - return GLTypes; - } - - #endregion - - #region public virtual Dictionary ReadCSTypeMap(StreamReader specFile) - - public virtual Dictionary ReadCSTypeMap(StreamReader specFile) - { - Dictionary CSTypes = new Dictionary(); - Console.WriteLine("Reading C# types."); - - while (!specFile.EndOfStream) - { - string line = specFile.ReadLine(); - if (String.IsNullOrEmpty(line) || line.StartsWith("#")) - continue; - - string[] words = line.Split(" ,\t".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - if (words.Length < 2) - continue; - - if (((Settings.Compatibility & Settings.Legacy.NoBoolParameters) != Settings.Legacy.None) && words[1] == "bool") - words[1] = "Int32"; - - CSTypes.Add(words[0], words[1]); - } - - return CSTypes; - } - - #endregion - - #region private string NextValidLine(StreamReader sr) - - private string NextValidLine(StreamReader sr) - { - string line; - - do - { - if (sr.EndOfStream) - return null; - - line = sr.ReadLine().Trim(); - - if (String.IsNullOrEmpty(line) || - line.StartsWith("#") || // Disregard comments. - line.StartsWith("passthru") || // Disregard passthru statements. - line.StartsWith("required-props:") || - line.StartsWith("param:") || - line.StartsWith("dlflags:") || - line.StartsWith("glxflags:") || - line.StartsWith("vectorequiv:") || - //line.StartsWith("category:") || - line.StartsWith("version:") || - line.StartsWith("glxsingle:") || - line.StartsWith("glxropcode:") || - line.StartsWith("glxvendorpriv:") || - line.StartsWith("glsflags:") || - line.StartsWith("glsopcode:") || - line.StartsWith("glsalias:") || - line.StartsWith("wglflags:") || - line.StartsWith("extension:") || - line.StartsWith("alias:") || - line.StartsWith("offset:")) - continue; - - return line; - } - while (true); - } - - #endregion - - #endregion - - #region ISpecWriter Members - - #region void WriteBindings - - public void WriteBindings(DelegateCollection delegates, FunctionCollection wrappers, EnumCollection enums) - { - Console.WriteLine("Writing bindings to {0}", Settings.OutputPath); - if (!Directory.Exists(Settings.OutputPath)) - Directory.CreateDirectory(Settings.OutputPath); - - string temp_enums_file = Path.GetTempFileName(); - string temp_delegates_file = Path.GetTempFileName(); - string temp_core_file = Path.GetTempFileName(); - string temp_wrappers_file = Path.GetTempFileName(); - - // Enums - using (BindStreamWriter sw = new BindStreamWriter(temp_enums_file)) - { - WriteLicense(sw); - - sw.WriteLine("using System;"); - sw.WriteLine(); - - if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None) - { - sw.WriteLine("namespace {0}", Settings.OutputNamespace); - sw.WriteLine("{"); - sw.Indent(); - sw.WriteLine("static partial class {0}", Settings.OutputClass); - } - else - sw.WriteLine("namespace {0}", Settings.EnumsOutput); - - sw.WriteLine("{"); - - sw.Indent(); - WriteEnums(sw, enums); - sw.Unindent(); - - if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None) - { - sw.WriteLine("}"); - sw.Unindent(); - } - - sw.WriteLine("}"); - } - - // Delegates - using (BindStreamWriter sw = new BindStreamWriter(temp_delegates_file)) - { - WriteLicense(sw); - sw.WriteLine("namespace {0}", Settings.OutputNamespace); - sw.WriteLine("{"); - sw.Indent(); - - sw.WriteLine("using System;"); - sw.WriteLine("using System.Text;"); - sw.WriteLine("using System.Runtime.InteropServices;"); - - sw.WriteLine("#pragma warning disable 0649"); - WriteDelegates(sw, delegates); - - sw.Unindent(); - sw.WriteLine("}"); - } - - // Core - using (BindStreamWriter sw = new BindStreamWriter(temp_core_file)) - { - WriteLicense(sw); - sw.WriteLine("namespace {0}", Settings.OutputNamespace); - sw.WriteLine("{"); - sw.Indent(); - //specWriter.WriteTypes(sw, Bind.Structures.Type.CSTypes); - sw.WriteLine("using System;"); - sw.WriteLine("using System.Text;"); - sw.WriteLine("using System.Runtime.InteropServices;"); - - WriteImports(sw, delegates); - - sw.Unindent(); - sw.WriteLine("}"); - } - - // Wrappers - using (BindStreamWriter sw = new BindStreamWriter(temp_wrappers_file)) - { - WriteLicense(sw); - sw.WriteLine("namespace {0}", Settings.OutputNamespace); - sw.WriteLine("{"); - sw.Indent(); - - sw.WriteLine("using System;"); - sw.WriteLine("using System.Text;"); - sw.WriteLine("using System.Runtime.InteropServices;"); - - WriteWrappers(sw, wrappers, Type.CSTypes); - - sw.Unindent(); - sw.WriteLine("}"); - } - - string output_enums = Path.Combine(Settings.OutputPath, enumsFile); - string output_delegates = Path.Combine(Settings.OutputPath, delegatesFile); - string output_core = Path.Combine(Settings.OutputPath, importsFile); - string output_wrappers = Path.Combine(Settings.OutputPath, wrappersFile); - - if (File.Exists(output_enums)) File.Delete(output_enums); - if (File.Exists(output_delegates)) File.Delete(output_delegates); - if (File.Exists(output_core)) File.Delete(output_core); - if (File.Exists(output_wrappers)) File.Delete(output_wrappers); - - File.Move(temp_enums_file, output_enums); - File.Move(temp_delegates_file, output_delegates); - File.Move(temp_core_file, output_core); - File.Move(temp_wrappers_file, output_wrappers); - } - - #endregion - - #region void WriteDelegates - - public virtual void WriteDelegates(BindStreamWriter sw, DelegateCollection delegates) - { - Trace.WriteLine(String.Format("Writing delegates to:\t{0}.{1}.{2}", Settings.OutputNamespace, Settings.OutputClass, Settings.DelegatesClass)); - - sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute - sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments - - sw.WriteLine(); - sw.WriteLine("partial class {0}", Settings.OutputClass); - sw.WriteLine("{"); - sw.Indent(); - - sw.WriteLine("internal static partial class {0}", Settings.DelegatesClass); - sw.WriteLine("{"); - sw.Indent(); - - foreach (Delegate d in delegates.Values) - { - sw.WriteLine("[System.Security.SuppressUnmanagedCodeSecurity()]"); - sw.WriteLine("internal {0};", d.ToString()); - sw.WriteLine("internal {0}static {1} {2}{1};", // = null - d.Unsafe ? "unsafe " : "", - d.Name, - Settings.FunctionPrefix); - } - - sw.Unindent(); - sw.WriteLine("}"); - - sw.Unindent(); - sw.WriteLine("}"); - } - - #endregion - - #region void WriteImports - - public virtual void WriteImports(BindStreamWriter sw, DelegateCollection delegates) - { - Trace.WriteLine(String.Format("Writing imports to:\t{0}.{1}.{2}", Settings.OutputNamespace, Settings.OutputClass, Settings.ImportsClass)); - - sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute - sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments - - sw.WriteLine(); - sw.WriteLine("partial class {0}", Settings.OutputClass); - sw.WriteLine("{"); - sw.Indent(); - sw.WriteLine(); - sw.WriteLine("internal static partial class {0}", Settings.ImportsClass); - sw.WriteLine("{"); - sw.Indent(); - //sw.WriteLine("static {0}() {1} {2}", Settings.ImportsClass, "{", "}"); // Disable BeforeFieldInit - sw.WriteLine(); - foreach (Delegate d in delegates.Values) - { - sw.WriteLine("[System.Security.SuppressUnmanagedCodeSecurity()]"); - sw.WriteLine( - "[System.Runtime.InteropServices.DllImport({0}.Library, EntryPoint = \"{1}{2}\"{3})]", - Settings.OutputClass, - Settings.FunctionPrefix, - d.Name, - d.Name.EndsWith("W") || d.Name.EndsWith("A") ? ", CharSet = CharSet.Auto" : ", ExactSpelling = true" - ); - sw.WriteLine("internal extern static {0};", d.DeclarationString()); - } - sw.Unindent(); - sw.WriteLine("}"); - sw.Unindent(); - sw.WriteLine("}"); - } - - #endregion - - #region void WriteWrappers - - public void WriteWrappers(BindStreamWriter sw, FunctionCollection wrappers, Dictionary CSTypes) - { - Trace.WriteLine(String.Format("Writing wrappers to:\t{0}.{1}", Settings.OutputNamespace, Settings.OutputClass)); - - sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute - sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments - sw.WriteLine("#pragma warning disable 1572"); // Wrong param comments - sw.WriteLine("#pragma warning disable 1573"); // Missing param comments - - sw.WriteLine(); - sw.WriteLine("partial class {0}", Settings.OutputClass); - sw.WriteLine("{"); - - sw.Indent(); - //sw.WriteLine("static {0}() {1} {2}", className, "{", "}"); // Static init in GLHelper.cs - sw.WriteLine(); - - int current = 0; - foreach (string key in wrappers.Keys) - { - if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core") - { - if (!Char.IsDigit(key[0])) - { - sw.WriteLine("public static partial class {0}", key); - } - else - { - // Identifiers cannot start with a number: - sw.WriteLine("public static partial class {0}{1}", Settings.ConstantPrefix, key); - } - sw.WriteLine("{"); - sw.Indent(); - } - - wrappers[key].Sort(); - foreach (Function f in wrappers[key]) - { - current = WriteWrapper(sw, current, f); - } - - if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core") - { - sw.Unindent(); - sw.WriteLine("}"); - sw.WriteLine(); - } - } - sw.Unindent(); - sw.WriteLine("}"); - } - - private static int WriteWrapper(BindStreamWriter sw, int current, Function f) - { - if ((Settings.Compatibility & Settings.Legacy.NoDocumentation) == 0) - { - Console.WriteLine("Creating docs for #{0} ({1})", current++, f.Name); - WriteDocumentation(sw, f); - } - WriteMethod(sw, f); - return current; - } - - private static void WriteMethod(BindStreamWriter sw, Function f) - { - if (f.Deprecated && Settings.IsEnabled(Settings.Legacy.AddDeprecationWarnings)) - { - sw.WriteLine("[Obsolete(\"Deprecated in OpenGL {0}\")]", f.DeprecatedVersion); - } - - if (!f.CLSCompliant) - { - sw.WriteLine("[System.CLSCompliant(false)]"); - } - - sw.WriteLine("[AutoGenerated(Category = \"{0}\", Version = \"{1}\", EntryPoint = \"{2}\")]", - f.Category, f.Version, Settings.FunctionPrefix + f.WrappedDelegate.Name); - sw.WriteLine("public static "); - sw.Write(f); - sw.WriteLine(); - } - - static DocProcessor processor = new DocProcessor(Path.Combine(Settings.DocPath, Settings.DocFile)); - static Dictionary docfiles; - private static void WriteDocumentation(BindStreamWriter sw, Function f) - { - if (docfiles == null) - { - docfiles = new Dictionary(); - foreach (string file in Directory.GetFiles(Settings.DocPath)) - { - docfiles.Add(Path.GetFileName(file), file); - } - } - - string docfile = null; - try - { - docfile = Settings.FunctionPrefix + f.WrappedDelegate.Name + ".xml"; - if (!docfiles.ContainsKey(docfile)) - docfile = Settings.FunctionPrefix + f.TrimmedName + ".xml"; - if (!docfiles.ContainsKey(docfile)) - docfile = Settings.FunctionPrefix + f.TrimmedName.TrimEnd(numbers) + ".xml"; - - string doc = null; - if (docfiles.ContainsKey(docfile)) - { - doc = processor.ProcessFile(docfiles[docfile]); - } - if (doc == null) - { - doc = "/// "; - } - - int summary_start = doc.IndexOf("") + "".Length; - string warning = "[deprecated: v{0}]"; - string category = "[requires: {0}]"; - if (f.Deprecated) - { - warning = String.Format(warning, f.DeprecatedVersion); - doc = doc.Insert(summary_start, warning); - } - - if (f.Extension != "Core" && !String.IsNullOrEmpty(f.Category)) - { - category = String.Format(category, f.Category); - doc = doc.Insert(summary_start, category); - } - else if (!String.IsNullOrEmpty(f.Version)) - { - if (f.Category.StartsWith("VERSION")) - category = String.Format(category, "v" + f.Version); - else - category = String.Format(category, "v" + f.Version + " and " + f.Category); - doc = doc.Insert(summary_start, category); - } - - sw.WriteLine(doc); - } - catch (Exception e) - { - Console.WriteLine("[Warning] Error processing file {0}: {1}", docfile, e.ToString()); - } - } - - #endregion - - #region void WriteTypes - - public void WriteTypes(BindStreamWriter sw, Dictionary CSTypes) - { - sw.WriteLine(); - foreach (string s in CSTypes.Keys) - { - sw.WriteLine("using {0} = System.{1};", s, CSTypes[s]); - } - } - - #endregion - - #region void WriteEnums - - public void WriteEnums(BindStreamWriter sw, EnumCollection enums) - { - //sw.WriteLine("#pragma warning disable 3019"); // CLSCompliant attribute - sw.WriteLine("#pragma warning disable 1591"); // Missing doc comments - sw.WriteLine(); - - if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None) - Trace.WriteLine(String.Format("Writing enums to:\t{0}.{1}.{2}", Settings.OutputNamespace, Settings.OutputClass, Settings.NestedEnumsClass)); - else - Trace.WriteLine(String.Format("Writing enums to:\t{0}", Settings.EnumsOutput)); - - if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) == Settings.Legacy.None) - { - if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None && - !String.IsNullOrEmpty(Settings.NestedEnumsClass)) - { - sw.WriteLine("public class Enums"); - sw.WriteLine("{"); - sw.Indent(); - } - - foreach (Enum @enum in enums.Values) - { - sw.Write(@enum); - sw.WriteLine(); - } - - if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None && - !String.IsNullOrEmpty(Settings.NestedEnumsClass)) - { - sw.Unindent(); - sw.WriteLine("}"); - } - } - else - { - // Tao legacy mode: dump all enums as constants in GLClass. - foreach (Constant c in enums[Settings.CompleteEnumName].ConstantCollection.Values) - { - // Print constants avoiding circular definitions - if (c.Name != c.Value) - { - sw.WriteLine(String.Format( - "public const int {0} = {2}((int){1});", - c.Name.StartsWith(Settings.ConstantPrefix) ? c.Name : Settings.ConstantPrefix + c.Name, - Char.IsDigit(c.Value[0]) ? c.Value : c.Value.StartsWith(Settings.ConstantPrefix) ? c.Value : Settings.ConstantPrefix + c.Value, - c.Unchecked ? "unchecked" : "")); - } - else - { - } - } - } - } - - #endregion - - #region void WriteLicense - - public void WriteLicense(BindStreamWriter sw) - { - sw.WriteLine(File.ReadAllText(Path.Combine(Settings.InputPath, Settings.LicenseFile))); - sw.WriteLine(); - } - - #endregion - - #endregion } } diff --git a/Source/Bind/Generator.Bind.csproj b/Source/Bind/Generator.Bind.csproj index 6e3763c4..4b859921 100644 --- a/Source/Bind/Generator.Bind.csproj +++ b/Source/Bind/Generator.Bind.csproj @@ -139,6 +139,7 @@ Properties\GlobalAssemblyInfo.cs + @@ -199,6 +200,7 @@ Code + OpenTK.snk @@ -938,9 +940,125 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer - + diff --git a/Source/Bind/IBind.cs b/Source/Bind/IBind.cs index 2dce32ab..ea21f003 100644 --- a/Source/Bind/IBind.cs +++ b/Source/Bind/IBind.cs @@ -6,7 +6,7 @@ namespace Bind { - interface IBind : ISpecReader, ISpecWriter + interface IBind { void Process(); } diff --git a/Source/Bind/Structures/Type.cs b/Source/Bind/Structures/Type.cs index fc7c92cb..9cf12cbe 100644 --- a/Source/Bind/Structures/Type.cs +++ b/Source/Bind/Structures/Type.cs @@ -16,38 +16,10 @@ namespace Bind.Structures internal static Dictionary GLTypes; internal static Dictionary CSTypes; - private static bool typesLoaded; - string current_qualifier = "", previous_qualifier = ""; - #region internal static void Initialize(string glTypes, string csTypes) - - internal static void Initialize(string glTypes, string csTypes) - { - if (!typesLoaded) - { - if (GLTypes == null) - { - using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, glTypes)) - { - GLTypes = MainClass.Generator.ReadTypeMap(sr); - } - } - if (CSTypes == null) - { - using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, csTypes)) - { - CSTypes = MainClass.Generator.ReadCSTypeMap(sr); - } - } - typesLoaded = true; - } - } - - #endregion - #region --- Constructors --- - + public Type() { } @@ -66,7 +38,7 @@ namespace Bind.Structures ElementCount = t.ElementCount; } } - + #endregion public string CurrentQualifier @@ -81,7 +53,8 @@ namespace Bind.Structures private set { previous_qualifier = value; } } - public string QualifiedType { + public string QualifiedType + { get { if (!String.IsNullOrEmpty(CurrentQualifier)) @@ -233,7 +206,7 @@ namespace Bind.Structures get { bool compliant = true; - + switch (CurrentType.ToLower()) { case "sbyte": @@ -244,16 +217,16 @@ namespace Bind.Structures case "uint16": case "uint32": case "uint64": - compliant = false; + compliant = false; break; - + default: compliant = Pointer == 0; - break; + break; } return compliant; - + /* if (Pointer != 0) { @@ -265,7 +238,7 @@ namespace Bind.Structures */ //return compliant && (!Pointer || CurrentType.Contains("IntPtr")); //return compliant && !(Pointer && ((Settings.Compatibility & Settings.Legacy.NoPublicUnsafeFunctions) == Settings.Legacy.None)); - + /* * return !( (Pointer && ((Settings.Compatibility & Settings.Legacy.NoPublicUnsafeFunctions) == Settings.Legacy.None ) || @@ -341,12 +314,12 @@ namespace Bind.Structures #endregion #region public override string ToString() - + public override string ToString() { return QualifiedType; } - + #endregion #region public virtual void Translate(XPathNavigator overrides, string category) diff --git a/Source/Bind/XmlSpecReader.cs b/Source/Bind/XmlSpecReader.cs new file mode 100644 index 00000000..75a7f266 --- /dev/null +++ b/Source/Bind/XmlSpecReader.cs @@ -0,0 +1,292 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.XPath; +using Bind.Structures; + +namespace Bind +{ + using Delegate = Bind.Structures.Delegate; + using Enum = Bind.Structures.Enum; + + class XmlSpecReader : ISpecReader + { + readonly string functionOverridesFile; + + public XmlSpecReader(string functionOverridesFile) + { + this.functionOverridesFile = functionOverridesFile; + } + + public DelegateCollection ReadDelegates(StreamReader specFile) + { + DelegateCollection delegates = new DelegateCollection(); + XPathDocument specs = new XPathDocument(specFile); + XPathDocument overrides = new XPathDocument(new StreamReader( + Path.Combine(Settings.InputPath, functionOverridesFile))); + + foreach (XPathNavigator nav in new XPathNavigator[] { + specs.CreateNavigator().SelectSingleNode("/signatures"), + overrides.CreateNavigator().SelectSingleNode("/overrides/add") }) + { + if (nav != null) + { + foreach (XPathNavigator node in nav.SelectChildren("function", String.Empty)) + { + var name = node.GetAttribute("name", String.Empty); + + // Check whether we are adding to an existing delegate or creating a new one. + Delegate d = null; + if (delegates.ContainsKey(name)) + { + d = delegates[name]; + } + else + { + d = new Delegate(); + d.Name = name; + d.Version = node.GetAttribute("version", String.Empty); + d.Category = node.GetAttribute("category", String.Empty); + d.DeprecatedVersion = node.GetAttribute("deprecated", String.Empty); + d.Deprecated = !String.IsNullOrEmpty(d.DeprecatedVersion); + } + + foreach (XPathNavigator param in node.SelectChildren(XPathNodeType.Element)) + { + switch (param.Name) + { + case "returns": + d.ReturnType.CurrentType = param.GetAttribute("type", String.Empty); + break; + + case "param": + Parameter p = new Parameter(); + p.CurrentType = param.GetAttribute("type", String.Empty); + p.Name = param.GetAttribute("name", String.Empty); + + string element_count = param.GetAttribute("elementcount", String.Empty); + if (String.IsNullOrEmpty(element_count)) + element_count = param.GetAttribute("count", String.Empty); + if (!String.IsNullOrEmpty(element_count)) + p.ElementCount = Int32.Parse(element_count); + + p.Flow = Parameter.GetFlowDirection(param.GetAttribute("flow", String.Empty)); + + d.Parameters.Add(p); + break; + } + } + + delegates.Add(d); + } + } + } + + return delegates; + } + + public Dictionary ReadTypeMap(StreamReader specFile) + { + Console.WriteLine("Reading opengl types."); + Dictionary GLTypes = new Dictionary(); + + if (specFile == null) + return GLTypes; + + do + { + string line = specFile.ReadLine(); + + if (String.IsNullOrEmpty(line) || line.StartsWith("#")) + continue; + + string[] words = line.Split(" ,*\t".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + + if (words[0].ToLower() == "void") + { + // Special case for "void" -> "". We make it "void" -> "void" + GLTypes.Add(words[0], "void"); + } + else if (words[0] == "VoidPointer" || words[0] == "ConstVoidPointer") + { + // "(Const)VoidPointer" -> "void*" + GLTypes.Add(words[0], "void*"); + } + else if (words[0] == "CharPointer" || words[0] == "charPointerARB") + { + // The typematching logic cannot handle pointers to pointers, e.g. CharPointer* -> char** -> string* -> string[]. + // Hence we give it a push. + // Note: When both CurrentType == "String" and Pointer == true, the typematching is hardcoded to use + // String[] or StringBuilder[]. + GLTypes.Add(words[0], "String"); + } + /*else if (words[0].Contains("Pointer")) + { + GLTypes.Add(words[0], words[1].Replace("Pointer", "*")); + }*/ + else if (words[1].Contains("GLvoid")) + { + GLTypes.Add(words[0], "void"); + } + else if (words[1] == "const" && words[2] == "GLubyte") + { + GLTypes.Add(words[0], "String"); + } + else if (words[1] == "struct") + { + GLTypes.Add(words[0], words[2]); + } + else + { + GLTypes.Add(words[0], words[1]); + } + } + while (!specFile.EndOfStream); + + return GLTypes; + } + + public Dictionary ReadCSTypeMap(StreamReader specFile) + { + Dictionary CSTypes = new Dictionary(); + Console.WriteLine("Reading C# types."); + + while (!specFile.EndOfStream) + { + string line = specFile.ReadLine(); + if (String.IsNullOrEmpty(line) || line.StartsWith("#")) + continue; + + string[] words = line.Split(" ,\t".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + if (words.Length < 2) + continue; + + if (((Settings.Compatibility & Settings.Legacy.NoBoolParameters) != Settings.Legacy.None) && words[1] == "bool") + words[1] = "Int32"; + + CSTypes.Add(words[0], words[1]); + } + + return CSTypes; + } + + public EnumCollection ReadEnums(StreamReader specFile) + { + // First, read all enum definitions from spec and override file. + // Afterwards, read all token/enum overrides from overrides file. + // Every single enum is merged into + + EnumCollection enums = new EnumCollection(); + Enum all = new Enum() { Name = Settings.CompleteEnumName }; + XPathDocument specs = new XPathDocument(specFile); + XPathDocument overrides = new XPathDocument(new StreamReader(Path.Combine(Settings.InputPath, functionOverridesFile))); + + foreach (XPathNavigator nav in new XPathNavigator[] { + specs.CreateNavigator().SelectSingleNode("/signatures"), + overrides.CreateNavigator().SelectSingleNode("/overrides/add") }) + { + if (nav != null) + { + foreach (XPathNavigator node in nav.SelectChildren("enum", String.Empty)) + { + Enum e = new Enum() + { + Name = node.GetAttribute("name", String.Empty), + Type = node.GetAttribute("type", String.Empty) + }; + if (String.IsNullOrEmpty(e.Name)) + throw new InvalidOperationException(String.Format("Empty name for enum element {0}", node.ToString())); + + foreach (XPathNavigator param in node.SelectChildren(XPathNodeType.Element)) + { + Constant c = null; + switch (param.Name) + { + case "token": + c = new Constant + { + Name = param.GetAttribute("name", String.Empty), + Value = param.GetAttribute("value", String.Empty) + }; + break; + + case "use": + c = new Constant + { + Name = param.GetAttribute("token", String.Empty), + Reference = param.GetAttribute("enum", String.Empty), + Value = param.GetAttribute("token", String.Empty), + }; + break; + + default: + throw new NotSupportedException(); + } + Utilities.Merge(all, c); + try + { + if (!e.ConstantCollection.ContainsKey(c.Name)) + { + e.ConstantCollection.Add(c.Name, c); + } + else if (e.ConstantCollection[c.Name].Value != c.Value) + { + var existing = e.ConstantCollection[c.Name]; + if (existing.Reference != null && c.Reference == null) + { + e.ConstantCollection[c.Name] = c; + } + else if (existing.Reference == null && c.Reference != null) + { } // Keep existing + else + { + Console.WriteLine("[Warning] Conflicting token {0}.{1} with value {2} != {3}", + e.Name, c.Name, e.ConstantCollection[c.Name].Value, c.Value); + } + } + } + catch (ArgumentException ex) + { + Console.WriteLine("[Warning] Failed to add constant {0} to enum {1}: {2}", c.Name, e.Name, ex.Message); + } + } + + Utilities.Merge(enums, e); + } + } + } + + Utilities.Merge(enums, all); + return enums; + } + } +}