Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

317 lines
7.1 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using Monodoc;
using Monodoc.Generators;
namespace Monodoc.Generators.Html
{
public class Man2Html : IHtmlExporter
{
public string CssCode {
get {
return string.Empty;
}
}
public string Export (Stream input, Dictionary<string, string> extraArgs)
{
if (input == null)
return null;
return GetTextFromReader (new StreamReader (input));
}
public string Export (string input, Dictionary<string, string> extraArgs)
{
if (string.IsNullOrEmpty (input))
return null;
return GetTextFromReader (new StringReader (input));
}
public static string GetTextFromReader (TextReader file)
{
string line;
StateInfo s = new StateInfo ();
while ((line = file.ReadLine ()) != null)
ProcessLine (line, s);
return s.output.ToString ();
}
enum ListState {
None,
Start,
Title,
}
class StateInfo {
public ListState ls;
public Stack<string> tags = new Stack<string> ();
public StringBuilder output = new StringBuilder ();
}
static void ProcessLine (string line, StateInfo s)
{
string[] parts = SplitLine (line);
switch (parts [0]) {
case ".\\\"": // comments
case ".de": // define macro
case ".if": // if
case ".ne": // ???
case "..": // end macro
// ignore
break;
case ".I":
s.output.Append ("<i>");
Translate (parts, 1, s.output);
s.output.Append ("</i>");
break;
case ".B":
s.output.Append ("<b>");
Translate (parts, 1, s.output);
s.output.Append ("</b>");
break;
case ".br":
Translate (parts, 1, s.output);
s.output.Append ("<br />");
break;
case ".nf":
Expect (s, "</p>");
s.output.Append ("<pre>\n");
s.tags.Push ("</pre>");
break;
case ".fi":
Expect (s, "</pre>");
break;
case ".PP":
Expect (s, "</p>", "</dd>", "</dl>");
goto case ".Sp";
case ".Sp":
Expect (s, "</p>");
s.output.Append ("<p>");
Translate (parts, 1, s.output);
s.tags.Push ("</p>");
break;
case ".RS":
Expect (s, "</p>");
s.output.Append ("<blockquote>");
s.tags.Push ("</blockquote>");
break;
case ".RE":
ClearUntil (s, "</blockquote>");
break;
case ".SH":
ClearAll (s);
s.output.Append ("<h2>");
Translate (parts, 1, s.output);
s.output.Append ("</h2>")
.Append ("<blockquote>");
s.tags.Push ("</blockquote>");
break;
case ".SS":
s.output.Append ("<h3>");
Translate (parts, 1, s.output);
s.output.Append ("</h3>");
break;
case ".TH": {
ClearAll (s);
string name = "", extra = "";
if (parts.Length >= 4 && parts [2].Trim ().Length == 0) {
name = parts [1] + "(" + parts [3] + ")";
if (parts.Length > 4) {
int start = 4;
if (parts [start].Trim ().Length == 0)
++start;
extra = string.Join ("", parts, start, parts.Length-start);
}
}
else
name = string.Join ("", parts, 1, parts.Length-1);
s.output.Append ("<table width=\"100%\" bgcolor=\"#b0c4da\">" +
"<tr colspan=\"2\"><td>Manual Pages</td></tr>\n" +
"<tr><td><h3>");
Translate (name, s.output);
s.output.Append ("</h3></td><td align=\"right\">");
Translate (extra, s.output);
s.output.Append ("</td></tr></table>");
break;
}
case ".TP":
Expect (s, "</p>");
if (s.tags.Count > 0 && s.tags.Peek ().ToString () != "</dd>") {
s.output.Append ("<dl>");
s.tags.Push ("</dl>");
}
else
Expect (s, "</dd>");
s.output.Append ("<dt>");
s.tags.Push ("</dt>");
s.ls = ListState.Start;
break;
default:
Translate (line, s.output);
break;
}
if (s.ls == ListState.Start)
s.ls = ListState.Title;
else if (s.ls == ListState.Title) {
Expect (s, "</dt>");
s.output.Append ("<dd>");
s.tags.Push ("</dd>");
s.ls = ListState.None;
}
s.output.Append ("\n");
}
static string[] SplitLine (string line)
{
if (line.Length > 1 && line [0] != '.')
return new string[]{null, line};
int i;
for (i = 0; i < line.Length; ++i) {
if (char.IsWhiteSpace (line, i))
break;
}
if (i == line.Length)
return new string[]{line};
var pieces = new List<string> ();
pieces.Add (line.Substring (0, i));
bool inQuotes = false;
bool prevWs = true;
++i;
int start = i;
for ( ; i < line.Length; ++i) {
char c = line [i];
if (inQuotes) {
if (c == '"') {
Add (pieces, line, start, i);
start = i+1;
inQuotes = false;
}
}
else {
if (prevWs && c == '"') {
Add (pieces, line, start, i);
start = i+1;
inQuotes = true;
}
else if (char.IsWhiteSpace (c)) {
if (!prevWs) {
Add (pieces, line, start, i);
start = i;
}
prevWs = true;
}
else {
if (prevWs) {
Add (pieces, line, start, i);
start = i;
}
prevWs = false;
}
}
}
if (start > 0 && start != line.Length)
pieces.Add (line.Substring (start, line.Length-start));
return pieces.ToArray ();
}
static void Add (List<string> pieces, string line, int start, int end)
{
if (start == end)
return;
pieces.Add (line.Substring (start, end-start));
}
static void Expect (StateInfo s, params string[] expected)
{
string e;
while (s.tags.Count > 0 &&
Array.IndexOf (expected, (e = s.tags.Peek ().ToString ())) >= 0) {
s.output.Append (s.tags.Pop ().ToString ());
}
}
static void ClearUntil (StateInfo s, string required)
{
string e = null;
while (s.tags.Count > 0 &&
(e = s.tags.Peek ().ToString ()) != required) {
s.output.Append (s.tags.Pop ().ToString ());
}
if (e == required)
s.output.Append (s.tags.Pop ().ToString ());
}
static void ClearAll (StateInfo s)
{
while (s.tags.Count > 0)
s.output.Append (s.tags.Pop ().ToString ());
}
static void Translate (string[] lines, int startIndex, StringBuilder output)
{
if (lines.Length <= startIndex)
return;
do {
Translate (lines [startIndex++], output);
if (startIndex == lines.Length)
break;
} while (startIndex < lines.Length);
}
static void Translate (string line, StringBuilder output)
{
string span = null;
int start = output.Length;
for (int i = 0; i < line.Length; ++i) {
switch (line [i]) {
case '\\': {
if ((i+2) < line.Length && line [i+1] == 'f') {
if (line [i+2] == 'I') {
output.Append ("<i>");
span = "</i>";
}
else if (line [i+2] == 'B') {
output.Append ("<b>");
span = "</b>";
}
else if (line [i+2] == 'R' || line [i+2] == 'P') {
output.Append (span);
}
else
goto default;
i += 2;
}
else if ((i+1) < line.Length) {
output.Append (line [i+1]);
++i;
}
else
goto default;
break;
}
case '<':
output.Append ("&lt;");
break;
case '>':
output.Append ("&gt;");
break;
case '&':
output.Append ("&amp;");
break;
default:
output.Append (line [i]);
break;
}
}
}
}
}