2013-12-01 21:17:15 +01:00
|
|
|
|
#region License
|
2013-10-11 01:58:54 +02:00
|
|
|
|
//
|
|
|
|
|
// 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 char[] numbers = "0123456789".ToCharArray();
|
2013-11-01 09:27:46 +01:00
|
|
|
|
IBind Generator { get; set; }
|
|
|
|
|
Settings Settings { get { return Generator.Settings; } }
|
2013-10-11 01:58:54 +02:00
|
|
|
|
|
2013-11-01 09:27:46 +01:00
|
|
|
|
#region ISpecWriter Members
|
2013-10-11 01:58:54 +02:00
|
|
|
|
|
|
|
|
|
public void WriteBindings(IBind generator)
|
|
|
|
|
{
|
2013-11-01 09:27:46 +01:00
|
|
|
|
Generator = generator;
|
2013-10-11 01:58:54 +02:00
|
|
|
|
WriteBindings(generator.Delegates, generator.Wrappers, generator.Enums);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 09:27:46 +01:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Private Members
|
|
|
|
|
|
|
|
|
|
private static void ConsoleRewrite(string text)
|
|
|
|
|
{
|
|
|
|
|
int left = Console.CursorLeft;
|
|
|
|
|
int top = Console.CursorTop;
|
|
|
|
|
Console.Write(text);
|
|
|
|
|
for (int i = text.Length; i < 80; i++)
|
|
|
|
|
Console.Write(" ");
|
|
|
|
|
Console.WriteLine();
|
|
|
|
|
Console.SetCursorPosition(left, top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region WriteBindings
|
|
|
|
|
|
2013-10-11 01:58:54 +02:00
|
|
|
|
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_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, wrappers);
|
|
|
|
|
sw.Unindent();
|
|
|
|
|
|
|
|
|
|
if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None)
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("}");
|
|
|
|
|
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;");
|
|
|
|
|
|
2013-11-24 13:54:52 +01:00
|
|
|
|
WriteWrappers(sw, wrappers, delegates, enums, Generator.CSTypes);
|
2013-10-11 01:58:54 +02:00
|
|
|
|
|
|
|
|
|
sw.Unindent();
|
|
|
|
|
sw.WriteLine("}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string output_enums = Path.Combine(Settings.OutputPath, Settings.EnumsFile);
|
|
|
|
|
string output_delegates = Path.Combine(Settings.OutputPath, Settings.DelegatesFile);
|
|
|
|
|
string output_core = Path.Combine(Settings.OutputPath, Settings.ImportsFile);
|
|
|
|
|
string output_wrappers = Path.Combine(Settings.OutputPath, Settings.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_wrappers_file, output_wrappers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region WriteWrappers
|
|
|
|
|
|
2013-11-24 13:54:52 +01:00
|
|
|
|
void WriteWrappers(BindStreamWriter sw, FunctionCollection wrappers,
|
|
|
|
|
DelegateCollection delegates, EnumCollection enums,
|
|
|
|
|
IDictionary<string, string> CSTypes)
|
2013-10-11 01:58:54 +02:00
|
|
|
|
{
|
|
|
|
|
Trace.WriteLine(String.Format("Writing wrappers to:\t{0}.{1}", Settings.OutputNamespace, Settings.OutputClass));
|
|
|
|
|
|
2013-11-26 01:31:29 +01:00
|
|
|
|
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("#pragma warning disable 626"); // extern method without DllImport
|
2013-10-11 01:58:54 +02:00
|
|
|
|
|
|
|
|
|
sw.WriteLine();
|
|
|
|
|
sw.WriteLine("partial class {0}", Settings.OutputClass);
|
|
|
|
|
sw.WriteLine("{");
|
|
|
|
|
sw.Indent();
|
2013-11-24 13:54:52 +01:00
|
|
|
|
|
|
|
|
|
// Write constructor
|
|
|
|
|
sw.WriteLine("static {0}()", Settings.OutputClass);
|
|
|
|
|
sw.WriteLine("{");
|
|
|
|
|
sw.Indent();
|
|
|
|
|
sw.WriteLine("EntryPointNames = new string[]", delegates.Count);
|
|
|
|
|
sw.WriteLine("{");
|
|
|
|
|
sw.Indent();
|
|
|
|
|
foreach (var d in delegates.Values.Select(d => d.First()))
|
2014-03-16 19:40:49 +01:00
|
|
|
|
{
|
|
|
|
|
if (!Settings.IsEnabled(Settings.Legacy.UseDllImports) || d.Extension != "Core")
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("\"{0}{1}\",", Settings.FunctionPrefix, d.Name);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-24 13:54:52 +01:00
|
|
|
|
sw.Unindent();
|
|
|
|
|
sw.WriteLine("};");
|
|
|
|
|
sw.WriteLine("EntryPoints = new IntPtr[EntryPointNames.Length];");
|
|
|
|
|
sw.Unindent();
|
|
|
|
|
sw.WriteLine("}");
|
2013-10-11 01:58:54 +02:00
|
|
|
|
sw.WriteLine();
|
|
|
|
|
|
2013-11-27 00:02:26 +01:00
|
|
|
|
int current_wrapper = 0;
|
2013-10-11 01:58:54 +02:00
|
|
|
|
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])
|
|
|
|
|
{
|
2013-11-27 00:02:26 +01:00
|
|
|
|
WriteWrapper(sw, f, enums);
|
|
|
|
|
current_wrapper++;
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core")
|
|
|
|
|
{
|
|
|
|
|
sw.Unindent();
|
|
|
|
|
sw.WriteLine("}");
|
|
|
|
|
sw.WriteLine();
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-27 00:02:26 +01:00
|
|
|
|
|
|
|
|
|
// Emit native signatures.
|
|
|
|
|
// These are required by the patcher.
|
|
|
|
|
int current_signature = 0;
|
|
|
|
|
foreach (var d in wrappers.Values.SelectMany(e => e).Select(w => w.WrappedDelegate).Distinct())
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("[Slot({0})]", d.Slot);
|
2013-12-01 21:17:15 +01:00
|
|
|
|
sw.WriteLine("[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]");
|
2013-11-27 00:02:26 +01:00
|
|
|
|
sw.WriteLine("static extern {0};", GetDeclarationString(d, false));
|
|
|
|
|
current_signature++;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-11 01:58:54 +02:00
|
|
|
|
sw.Unindent();
|
|
|
|
|
sw.WriteLine("}");
|
2013-11-27 00:02:26 +01:00
|
|
|
|
|
|
|
|
|
Console.WriteLine("Wrote {0} wrappers for {1} signatures", current_wrapper, current_signature);
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-27 00:02:26 +01:00
|
|
|
|
void WriteWrapper(BindStreamWriter sw, Function f, EnumCollection enums)
|
2013-10-11 01:58:54 +02:00
|
|
|
|
{
|
|
|
|
|
if ((Settings.Compatibility & Settings.Legacy.NoDocumentation) == 0)
|
|
|
|
|
{
|
|
|
|
|
WriteDocumentation(sw, f);
|
|
|
|
|
}
|
2013-11-01 09:27:46 +01:00
|
|
|
|
WriteMethod(sw, f, enums);
|
2013-11-03 01:27:33 +01:00
|
|
|
|
sw.WriteLine();
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 09:27:46 +01:00
|
|
|
|
private void WriteMethod(BindStreamWriter sw, Function f, EnumCollection enums)
|
2013-10-11 01:58:54 +02:00
|
|
|
|
{
|
2013-11-14 13:46:42 +01:00
|
|
|
|
if (!String.IsNullOrEmpty(f.Obsolete))
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("[Obsolete(\"{0}\")]", f.Obsolete);
|
|
|
|
|
}
|
|
|
|
|
else if (f.Deprecated && Settings.IsEnabled(Settings.Legacy.AddDeprecationWarnings))
|
2013-10-11 01:58:54 +02:00
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("[Obsolete(\"Deprecated in OpenGL {0}\")]", f.DeprecatedVersion);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-15 22:01:45 +01:00
|
|
|
|
sw.WriteLine("[AutoGenerated(Category = \"{0}\", Version = \"{1}\", EntryPoint = \"{2}\")]",
|
|
|
|
|
f.Category, f.Version, Settings.FunctionPrefix + f.WrappedDelegate.EntryPoint);
|
|
|
|
|
|
2013-10-11 01:58:54 +02:00
|
|
|
|
if (!f.CLSCompliant)
|
|
|
|
|
{
|
2013-12-15 22:01:45 +01:00
|
|
|
|
sw.WriteLine("[CLSCompliant(false)]");
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-15 18:27:24 +01:00
|
|
|
|
sw.WriteLine("public static {0} {{ throw new NotImplementedException(); }}", GetDeclarationString(f, Settings.Compatibility));
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 09:27:46 +01:00
|
|
|
|
DocProcessor processor_;
|
|
|
|
|
DocProcessor Processor
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (processor_ == null)
|
2014-03-30 10:29:11 +02:00
|
|
|
|
processor_ = new DocProcessor();
|
2013-11-01 09:27:46 +01:00
|
|
|
|
return processor_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Dictionary<string, string> docfiles;
|
2013-10-11 01:58:54 +02:00
|
|
|
|
void WriteDocumentation(BindStreamWriter sw, Function f)
|
|
|
|
|
{
|
|
|
|
|
if (docfiles == null)
|
|
|
|
|
{
|
|
|
|
|
docfiles = new Dictionary<string, string>();
|
|
|
|
|
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";
|
|
|
|
|
|
2014-03-28 20:08:38 +01:00
|
|
|
|
Documentation docs =
|
|
|
|
|
(docfiles.ContainsKey(docfile) ?
|
|
|
|
|
Processor.ProcessFile(docfiles[docfile]) :
|
|
|
|
|
null) ??
|
|
|
|
|
new Documentation
|
|
|
|
|
{
|
|
|
|
|
Summary = String.Empty,
|
|
|
|
|
Parameters = f.Parameters.Select(p =>
|
2014-03-30 10:43:30 +02:00
|
|
|
|
new DocumentationParameter(p.Name, String.Empty)).ToList()
|
2014-03-28 20:08:38 +01:00
|
|
|
|
};
|
2013-10-11 01:58:54 +02:00
|
|
|
|
|
2014-03-30 10:29:11 +02:00
|
|
|
|
string warning = String.Empty;
|
|
|
|
|
string category = String.Empty;
|
2013-10-11 01:58:54 +02:00
|
|
|
|
if (f.Deprecated)
|
|
|
|
|
{
|
2014-03-30 10:29:11 +02:00
|
|
|
|
warning = String.Format("[deprecated: v{0}]", f.DeprecatedVersion);
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (f.Extension != "Core" && !String.IsNullOrEmpty(f.Category))
|
|
|
|
|
{
|
2014-03-30 10:29:11 +02:00
|
|
|
|
category = String.Format("[requires: {0}]", f.Category);
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
else if (!String.IsNullOrEmpty(f.Version))
|
|
|
|
|
{
|
|
|
|
|
if (f.Category.StartsWith("VERSION"))
|
2014-03-30 10:29:11 +02:00
|
|
|
|
category = String.Format("[requires: {0}]", "v" + f.Version);
|
2013-10-11 01:58:54 +02:00
|
|
|
|
else
|
2014-03-30 10:29:11 +02:00
|
|
|
|
category = String.Format("[requires: {0}]", "v" + f.Version + " or " + f.Category);
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-30 10:29:11 +02:00
|
|
|
|
sw.WriteLine("/// <summary>{0}{1} {2}</summary>",
|
|
|
|
|
category, warning, docs.Summary);
|
2014-03-28 20:08:38 +01:00
|
|
|
|
for (int i = 0; i < f.Parameters.Count; i++)
|
2014-03-10 23:13:53 +01:00
|
|
|
|
{
|
2014-03-28 20:08:38 +01:00
|
|
|
|
var param = f.Parameters[i];
|
2014-03-30 10:29:11 +02:00
|
|
|
|
|
|
|
|
|
string length = String.Empty;
|
2014-03-28 20:08:38 +01:00
|
|
|
|
if (!String.IsNullOrEmpty(param.ComputeSize))
|
2014-03-10 23:13:53 +01:00
|
|
|
|
{
|
2014-03-30 10:29:11 +02:00
|
|
|
|
length = String.Format("[length: {0}]", param.ComputeSize);
|
2014-03-10 23:13:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-30 10:43:30 +02:00
|
|
|
|
// Try to match the correct parameter from documentation:
|
|
|
|
|
// - first by name
|
|
|
|
|
// - then by index
|
|
|
|
|
var docparam =
|
|
|
|
|
(docs.Parameters
|
|
|
|
|
.Where(p => p.Name == param.RawName)
|
|
|
|
|
.FirstOrDefault()) ??
|
|
|
|
|
(docs.Parameters.Count > i ?
|
|
|
|
|
docs.Parameters[i] : null);
|
|
|
|
|
|
|
|
|
|
if (docparam != null)
|
2014-03-30 10:29:11 +02:00
|
|
|
|
{
|
2014-03-30 10:43:30 +02:00
|
|
|
|
if (docparam.Name != param.RawName)
|
2014-03-30 10:29:11 +02:00
|
|
|
|
{
|
|
|
|
|
Console.Error.WriteLine(
|
|
|
|
|
"[Warning] Parameter '{0}' in function '{1}' has incorrect doc name '{2}'",
|
2014-03-30 10:43:30 +02:00
|
|
|
|
param.Name, f.Name, docparam.Name);
|
2014-03-30 10:29:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Note: we use param.Name, because the documentation sometimes
|
|
|
|
|
// uses different names than the specification.
|
|
|
|
|
sw.WriteLine("/// <param name=\"{0}\">{1} {2}</param>",
|
2014-03-30 10:43:30 +02:00
|
|
|
|
param.Name, length, docparam.Documentation);
|
2014-03-30 10:29:11 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Console.Error.WriteLine(
|
2014-03-30 10:43:30 +02:00
|
|
|
|
"[Warning] Parameter '{0}' in function '{1}' not found in '{2}: {{{3}}}'",
|
|
|
|
|
param.Name, f.Name, docfile,
|
|
|
|
|
String.Join(",", docs.Parameters.Select(p => p.Name).ToArray()));
|
2014-03-30 10:29:11 +02:00
|
|
|
|
sw.WriteLine("/// <param name=\"{0}\">{1}</param>",
|
|
|
|
|
param.Name, length);
|
|
|
|
|
}
|
2013-11-10 09:12:42 +01:00
|
|
|
|
}
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("[Warning] Error processing file {0}: {1}", docfile, e.ToString());
|
2014-03-30 10:29:11 +02:00
|
|
|
|
}
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region WriteTypes
|
|
|
|
|
|
|
|
|
|
public void WriteTypes(BindStreamWriter sw, Dictionary<string, string> CSTypes)
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine();
|
|
|
|
|
foreach (string s in CSTypes.Keys)
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("using {0} = System.{1};", s, CSTypes[s]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region WriteConstants
|
|
|
|
|
|
|
|
|
|
void WriteConstants(BindStreamWriter sw, IEnumerable<Constant> constants)
|
|
|
|
|
{
|
|
|
|
|
// Make sure everything is sorted. This will avoid random changes between
|
|
|
|
|
// consecutive runs of the program.
|
|
|
|
|
constants = constants.OrderBy(c => c);
|
|
|
|
|
|
|
|
|
|
foreach (var c in constants)
|
|
|
|
|
{
|
|
|
|
|
if (!Settings.IsEnabled(Settings.Legacy.NoDocumentation))
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("/// <summary>");
|
|
|
|
|
sw.WriteLine("/// Original was " + Settings.ConstantPrefix + c.OriginalName + " = " + c.Value);
|
|
|
|
|
sw.WriteLine("/// </summary>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var str = String.Format("{0} = {1}((int){2}{3})", c.Name, c.Unchecked ? "unchecked" : "",
|
|
|
|
|
!String.IsNullOrEmpty(c.Reference) ? c.Reference + Settings.NamespaceSeparator : "", c.Value);
|
|
|
|
|
|
|
|
|
|
sw.Write(str);
|
|
|
|
|
if (!String.IsNullOrEmpty(str))
|
|
|
|
|
sw.WriteLine(",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region WriteEnums
|
|
|
|
|
|
|
|
|
|
void WriteEnums(BindStreamWriter sw, EnumCollection enums, FunctionCollection wrappers)
|
|
|
|
|
{
|
|
|
|
|
//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();
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-16 23:41:12 +01:00
|
|
|
|
// Build a dictionary of which functions use which enums
|
|
|
|
|
var enum_counts = new Dictionary<Enum, List<Function>>();
|
|
|
|
|
foreach (var e in enums.Values)
|
|
|
|
|
{
|
|
|
|
|
// Initialize the dictionary
|
|
|
|
|
enum_counts.Add(e, new List<Function>());
|
|
|
|
|
}
|
|
|
|
|
foreach (var wrapper in wrappers.Values.SelectMany(w => w))
|
|
|
|
|
{
|
|
|
|
|
// Add every function to every enum parameter it references
|
|
|
|
|
foreach (var parameter in wrapper.Parameters.Where(p => p.IsEnum))
|
|
|
|
|
{
|
|
|
|
|
var e = enums[parameter.CurrentType];
|
|
|
|
|
var list = enum_counts[e];
|
|
|
|
|
list.Add(wrapper);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-11 01:58:54 +02:00
|
|
|
|
foreach (Enum @enum in enums.Values)
|
|
|
|
|
{
|
|
|
|
|
if (!Settings.IsEnabled(Settings.Legacy.NoDocumentation))
|
|
|
|
|
{
|
|
|
|
|
// Document which functions use this enum.
|
2013-11-16 23:41:12 +01:00
|
|
|
|
var functions = enum_counts[@enum]
|
|
|
|
|
.Select(w => Settings.GLClass + (w.Extension != "Core" ? ("." + w.Extension) : "") + "." + w.TrimmedName)
|
2013-10-11 01:58:54 +02:00
|
|
|
|
.Distinct();
|
|
|
|
|
|
|
|
|
|
sw.WriteLine("/// <summary>");
|
2013-11-01 09:27:46 +01:00
|
|
|
|
sw.WriteLine(String.Format("/// {0}",
|
|
|
|
|
functions.Count() >= 3 ?
|
|
|
|
|
String.Format("Used in {0} and {1} other function{2}",
|
|
|
|
|
String.Join(", ", functions.Take(2).ToArray()),
|
|
|
|
|
functions.Count() - 2,
|
|
|
|
|
functions.Count() - 2 > 1 ? "s" : "") :
|
|
|
|
|
functions.Count() >= 1 ?
|
|
|
|
|
String.Format("Used in {0}",
|
|
|
|
|
String.Join(", ", functions.ToArray())) :
|
|
|
|
|
"Not used directly."));
|
2013-10-11 01:58:54 +02:00
|
|
|
|
sw.WriteLine("/// </summary>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (@enum.IsFlagCollection)
|
|
|
|
|
sw.WriteLine("[Flags]");
|
|
|
|
|
sw.WriteLine("public enum " + @enum.Name + " : " + @enum.Type);
|
|
|
|
|
sw.WriteLine("{");
|
|
|
|
|
sw.Indent();
|
|
|
|
|
WriteConstants(sw, @enum.ConstantCollection.Values);
|
|
|
|
|
sw.Unindent();
|
|
|
|
|
sw.WriteLine("}");
|
|
|
|
|
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
|
2013-11-01 09:27:46 +01:00
|
|
|
|
|
|
|
|
|
// For example, if parameter foo has indirection level = 1, then it
|
|
|
|
|
// is consumed as 'foo*' in the fixed_statements and the call string.
|
|
|
|
|
readonly static string[] pointer_levels = new string[] { "", "*", "**", "***", "****" };
|
|
|
|
|
readonly static string[] array_levels = new string[] { "", "[]", "[,]", "[,,]", "[,,,]" };
|
|
|
|
|
|
|
|
|
|
static bool IsEnum(string s, EnumCollection enums)
|
|
|
|
|
{
|
|
|
|
|
return enums.ContainsKey(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string GetDeclarationString(Constant c)
|
|
|
|
|
{
|
|
|
|
|
if (String.IsNullOrEmpty(c.Name))
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Invalid Constant: Name is empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return String.Format("{0} = {1}((int){2}{3})",
|
|
|
|
|
c.Name,
|
|
|
|
|
c.Unchecked ? "unchecked" : String.Empty,
|
|
|
|
|
!String.IsNullOrEmpty(c.Reference) ?
|
|
|
|
|
c.Reference + Settings.NamespaceSeparator :
|
|
|
|
|
String.Empty,
|
|
|
|
|
c.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string GetDeclarationString(Delegate d, bool is_delegate)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
sb.Append(d.Unsafe ? "unsafe " : "");
|
|
|
|
|
if (is_delegate)
|
|
|
|
|
sb.Append("delegate ");
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(d.ReturnType, Settings.Legacy.ConstIntEnums));
|
2013-11-01 09:27:46 +01:00
|
|
|
|
sb.Append(" ");
|
2013-11-27 00:02:26 +01:00
|
|
|
|
sb.Append(Settings.FunctionPrefix);
|
2013-11-01 09:27:46 +01:00
|
|
|
|
sb.Append(d.Name);
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(d.Parameters, Settings.Legacy.ConstIntEnums));
|
2013-11-01 09:27:46 +01:00
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string GetDeclarationString(Enum e)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
List<Constant> constants = new List<Constant>(e.ConstantCollection.Values);
|
|
|
|
|
constants.Sort(delegate(Constant c1, Constant c2)
|
|
|
|
|
{
|
|
|
|
|
int ret = String.Compare(c1.Value, c2.Value);
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
return String.Compare(c1.Name, c2.Name);
|
|
|
|
|
return ret;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (e.IsFlagCollection)
|
|
|
|
|
sb.AppendLine("[Flags]");
|
|
|
|
|
sb.Append("public enum ");
|
|
|
|
|
sb.Append(e.Name);
|
|
|
|
|
sb.Append(" : ");
|
|
|
|
|
sb.AppendLine(e.Type);
|
|
|
|
|
sb.AppendLine("{");
|
|
|
|
|
|
|
|
|
|
foreach (Constant c in constants)
|
|
|
|
|
{
|
|
|
|
|
var declaration = GetDeclarationString(c);
|
|
|
|
|
sb.Append(" ");
|
|
|
|
|
sb.Append(declaration);
|
|
|
|
|
if (!String.IsNullOrEmpty(declaration))
|
|
|
|
|
sb.AppendLine(",");
|
|
|
|
|
}
|
|
|
|
|
sb.Append("}");
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-01 18:26:01 +01:00
|
|
|
|
string GetDeclarationString(Function f, Settings.Legacy settings)
|
2013-11-01 09:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
sb.Append(f.Unsafe ? "unsafe " : "");
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(f.ReturnType, settings));
|
2013-11-01 09:27:46 +01:00
|
|
|
|
sb.Append(" ");
|
|
|
|
|
if ((Settings.Compatibility & Settings.Legacy.NoTrimFunctionEnding) != Settings.Legacy.None)
|
|
|
|
|
{
|
|
|
|
|
sb.Append(Settings.FunctionPrefix);
|
|
|
|
|
}
|
|
|
|
|
sb.Append(!String.IsNullOrEmpty(f.TrimmedName) ? f.TrimmedName : f.Name);
|
|
|
|
|
|
|
|
|
|
if (f.Parameters.HasGenericParameters)
|
|
|
|
|
{
|
|
|
|
|
sb.Append("<");
|
|
|
|
|
foreach (Parameter p in f.Parameters)
|
|
|
|
|
{
|
|
|
|
|
if (p.Generic)
|
|
|
|
|
{
|
|
|
|
|
sb.Append(p.CurrentType);
|
|
|
|
|
sb.Append(",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sb.Remove(sb.Length - 1, 1);
|
|
|
|
|
sb.Append(">");
|
|
|
|
|
}
|
2013-11-27 00:02:26 +01:00
|
|
|
|
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(f.Parameters, settings));
|
2013-11-27 00:02:26 +01:00
|
|
|
|
|
2013-11-01 09:27:46 +01:00
|
|
|
|
if (f.Parameters.HasGenericParameters)
|
|
|
|
|
{
|
2013-11-27 00:02:26 +01:00
|
|
|
|
sb.AppendLine();
|
2013-11-01 09:27:46 +01:00
|
|
|
|
foreach (Parameter p in f.Parameters)
|
|
|
|
|
{
|
|
|
|
|
if (p.Generic)
|
|
|
|
|
sb.AppendLine(String.Format(" where {0} : struct", p.CurrentType));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-01 18:26:01 +01:00
|
|
|
|
string GetDeclarationString(Parameter p, bool override_unsafe_setting, Settings.Legacy settings)
|
2013-11-01 09:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
if (p.Flow == FlowDirection.Out)
|
|
|
|
|
sb.Append("[OutAttribute] ");
|
|
|
|
|
else if (p.Flow == FlowDirection.Undefined)
|
|
|
|
|
sb.Append("[InAttribute, OutAttribute] ");
|
|
|
|
|
|
|
|
|
|
if (p.Reference)
|
|
|
|
|
{
|
|
|
|
|
if (p.Flow == FlowDirection.Out)
|
|
|
|
|
sb.Append("out ");
|
|
|
|
|
else
|
|
|
|
|
sb.Append("ref ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!override_unsafe_setting && ((Settings.Compatibility & Settings.Legacy.NoPublicUnsafeFunctions) != Settings.Legacy.None))
|
|
|
|
|
{
|
|
|
|
|
if (p.Pointer != 0)
|
|
|
|
|
{
|
|
|
|
|
sb.Append("IntPtr");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(p as Type, settings));
|
2013-11-01 09:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(p as Type, settings));
|
2013-11-01 09:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
if (!String.IsNullOrEmpty(p.Name))
|
|
|
|
|
{
|
|
|
|
|
sb.Append(" ");
|
|
|
|
|
sb.Append(p.Name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-01 18:26:01 +01:00
|
|
|
|
string GetDeclarationString(ParameterCollection parameters, Settings.Legacy settings)
|
2013-11-01 09:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
sb.Append("(");
|
|
|
|
|
if (parameters.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (Parameter p in parameters)
|
|
|
|
|
{
|
2013-12-01 18:26:01 +01:00
|
|
|
|
sb.Append(GetDeclarationString(p, false, settings));
|
2013-11-01 09:27:46 +01:00
|
|
|
|
sb.Append(", ");
|
|
|
|
|
}
|
|
|
|
|
sb.Replace(", ", ")", sb.Length - 2, 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sb.Append(")");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-01 18:26:01 +01:00
|
|
|
|
string GetDeclarationString(Type type, Settings.Legacy settings)
|
2013-11-01 09:27:46 +01:00
|
|
|
|
{
|
2013-12-01 18:26:01 +01:00
|
|
|
|
var t = type.QualifiedType;
|
|
|
|
|
if ((settings & Settings.Legacy.ConstIntEnums) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (type.IsEnum)
|
|
|
|
|
{
|
|
|
|
|
t = "System.Int32";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 09:27:46 +01:00
|
|
|
|
return String.Format("{0}{1}{2}",
|
2013-12-01 18:26:01 +01:00
|
|
|
|
t,
|
2013-11-01 09:27:46 +01:00
|
|
|
|
pointer_levels[type.Pointer],
|
|
|
|
|
array_levels[type.Array]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2013-10-11 01:58:54 +02:00
|
|
|
|
}
|
|
|
|
|
}
|