2009-11-03 08:48:49 +00:00
|
|
|
using System;
|
2014-03-28 19:08:38 +00:00
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
2009-03-08 00:46:58 +00:00
|
|
|
using System.IO;
|
2014-03-28 19:08:38 +00:00
|
|
|
using System.Linq;
|
|
|
|
using System.Text;
|
2009-08-17 12:28:22 +00:00
|
|
|
using System.Text.RegularExpressions;
|
2009-03-08 00:46:58 +00:00
|
|
|
using System.Xml;
|
2014-03-28 19:08:38 +00:00
|
|
|
using System.Xml.Linq;
|
|
|
|
using System.Xml.XPath;
|
2009-03-08 00:46:58 +00:00
|
|
|
using System.Xml.Xsl;
|
|
|
|
|
2014-03-28 19:08:38 +00:00
|
|
|
using Bind.Structures;
|
|
|
|
|
2009-03-08 00:46:58 +00:00
|
|
|
namespace Bind
|
|
|
|
{
|
|
|
|
class DocProcessor
|
|
|
|
{
|
2010-11-21 14:24:05 +00:00
|
|
|
static readonly Regex remove_mathml = new Regex(
|
|
|
|
@"<(mml:math|inlineequation)[^>]*?>(?:.|\n)*?</\s*\1\s*>",
|
2009-03-08 00:46:58 +00:00
|
|
|
RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
|
|
|
|
|
2009-08-21 20:28:14 +00:00
|
|
|
static readonly XslCompiledTransform xslt = new XslCompiledTransform();
|
2009-03-08 00:46:58 +00:00
|
|
|
static readonly XmlReaderSettings settings = new XmlReaderSettings();
|
|
|
|
|
2014-03-28 19:08:38 +00:00
|
|
|
Documentation Cached;
|
2010-10-12 11:00:46 +00:00
|
|
|
string LastFile;
|
|
|
|
|
2009-03-08 00:46:58 +00:00
|
|
|
public DocProcessor(string transform_file)
|
|
|
|
{
|
2014-03-28 19:08:38 +00:00
|
|
|
if (!File.Exists(transform_file))
|
|
|
|
{
|
|
|
|
// If no specific transform file exists
|
|
|
|
// get the generic transform file from
|
|
|
|
// the parent directory
|
|
|
|
var dir = Directory.GetParent(Path.GetDirectoryName(transform_file)).FullName;
|
|
|
|
var file = Path.GetFileName(transform_file);
|
|
|
|
transform_file = Path.Combine(dir, file);
|
|
|
|
}
|
2009-03-08 00:46:58 +00:00
|
|
|
xslt.Load(transform_file);
|
|
|
|
settings.ProhibitDtd = false;
|
|
|
|
settings.XmlResolver = null;
|
|
|
|
}
|
|
|
|
|
2009-03-08 18:08:35 +00:00
|
|
|
// Strips MathML tags from the source and replaces the equations with the content
|
|
|
|
// found in the <!-- eqn: :--> comments in the docs.
|
|
|
|
// Todo: Some simple MathML tags do not include comments, find a solution.
|
|
|
|
// Todo: Some files include more than 1 function - find a way to map these extra functions.
|
2014-03-28 19:08:38 +00:00
|
|
|
public Documentation ProcessFile(string file)
|
2009-03-08 00:46:58 +00:00
|
|
|
{
|
2013-11-10 08:12:42 +00:00
|
|
|
string text;
|
|
|
|
|
2010-10-12 11:00:46 +00:00
|
|
|
if (LastFile == file)
|
2014-03-28 19:08:38 +00:00
|
|
|
return Cached;
|
2010-10-12 11:00:46 +00:00
|
|
|
|
|
|
|
LastFile = file;
|
2013-11-10 08:12:42 +00:00
|
|
|
text = File.ReadAllText(file);
|
2009-03-08 00:46:58 +00:00
|
|
|
|
2014-03-28 19:08:38 +00:00
|
|
|
text = text
|
|
|
|
.Replace("xml:", String.Empty) // Remove namespaces
|
|
|
|
.Replace("ε", "epsilon") // Fix unrecognized ε entities
|
|
|
|
.Replace("<constant>", "<c>") // Improve output
|
|
|
|
.Replace("</constant>", "</c>");
|
|
|
|
|
2013-11-10 08:12:42 +00:00
|
|
|
Match m = remove_mathml.Match(text);
|
2009-03-08 00:46:58 +00:00
|
|
|
while (m.Length > 0)
|
|
|
|
{
|
2013-11-10 08:12:42 +00:00
|
|
|
string removed = text.Substring(m.Index, m.Length);
|
|
|
|
text = text.Remove(m.Index, m.Length);
|
2009-03-08 18:08:35 +00:00
|
|
|
int equation = removed.IndexOf("eqn");
|
|
|
|
if (equation > 0)
|
|
|
|
{
|
2010-11-21 14:24:05 +00:00
|
|
|
// Find the start and end of the equation string
|
|
|
|
int eqn_start = equation + 4;
|
|
|
|
int eqn_end = removed.IndexOf(":-->") - equation - 4;
|
|
|
|
if (eqn_end < 0)
|
|
|
|
{
|
|
|
|
// Note: a few docs from man4 delimit eqn end with ": -->"
|
|
|
|
eqn_end = removed.IndexOf(": -->") - equation - 4;
|
|
|
|
}
|
|
|
|
if (eqn_end < 0)
|
|
|
|
{
|
|
|
|
Console.WriteLine("[Warning] Failed to find equation for mml.");
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
string eqn_substring = removed.Substring(eqn_start, eqn_end);
|
2013-11-10 08:12:42 +00:00
|
|
|
text = text.Insert(m.Index, "<![CDATA[" + eqn_substring + "]]>");
|
2009-03-08 18:08:35 +00:00
|
|
|
}
|
2010-11-21 14:24:05 +00:00
|
|
|
|
|
|
|
next:
|
2013-11-10 08:12:42 +00:00
|
|
|
m = remove_mathml.Match(text);
|
2009-03-08 00:46:58 +00:00
|
|
|
}
|
|
|
|
|
2014-03-28 19:08:38 +00:00
|
|
|
//XmlReader doc = null;
|
|
|
|
XDocument doc = null;
|
2009-03-08 18:08:35 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
// The pure XmlReader is ~20x faster than the XmlTextReader.
|
2014-03-28 19:08:38 +00:00
|
|
|
//doc = XmlReader.Create(new StringReader(text), settings);
|
|
|
|
doc = XDocument.Parse(text);
|
|
|
|
Cached = ToInlineDocs(doc);
|
|
|
|
return Cached;
|
2009-03-08 18:08:35 +00:00
|
|
|
}
|
|
|
|
catch (XmlException e)
|
2009-03-08 00:46:58 +00:00
|
|
|
{
|
2009-03-08 18:08:35 +00:00
|
|
|
Console.WriteLine(e.ToString());
|
|
|
|
Console.WriteLine(doc.ToString());
|
2014-03-28 19:08:38 +00:00
|
|
|
return null;
|
2009-03-08 00:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-28 19:08:38 +00:00
|
|
|
|
|
|
|
Documentation ToInlineDocs(XDocument doc)
|
|
|
|
{
|
|
|
|
var inline = new Documentation
|
|
|
|
{
|
|
|
|
Summary =
|
|
|
|
((IEnumerable)doc.XPathEvaluate("//*[name()='refentry']/*[name()='refnamediv']/*[name()='refpurpose']"))
|
|
|
|
.Cast<XElement>().First().Value.Trim(),
|
|
|
|
Parameters =
|
|
|
|
((IEnumerable)doc.XPathEvaluate("*[name()='refentry']/*[name()='refsect1'][@id='parameters']/*[name()='variablelist']/*[name()='varlistentry']"))
|
|
|
|
.Cast<XNode>()
|
|
|
|
.Select(p => new KeyValuePair<string, string>(
|
|
|
|
p.XPathSelectElement("*[name()='term']/*[name()='parameter']").Value.Trim(),
|
|
|
|
p.XPathSelectElement("*[name()='listitem']").Value.Trim()))
|
|
|
|
.ToList()
|
|
|
|
};
|
|
|
|
|
|
|
|
inline.Summary = Char.ToUpper(inline.Summary[0]) + inline.Summary.Substring(1);
|
|
|
|
return inline;
|
|
|
|
}
|
2009-03-08 00:46:58 +00:00
|
|
|
}
|
|
|
|
}
|