a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
317 lines
7.1 KiB
C#
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 ("<");
|
|
break;
|
|
case '>':
|
|
output.Append (">");
|
|
break;
|
|
case '&':
|
|
output.Append ("&");
|
|
break;
|
|
default:
|
|
output.Append (line [i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|