2 // A provider to display man pages
5 // Johannes Roith <johannes@roith.de>
6 // Jonathan Pryor <jpryor@novell.com>
8 // (C) 2008 Novell, Inc.
12 using System.Collections;
13 using System.Diagnostics;
19 // The simple provider generates the information source
21 public class ManProvider : Provider {
24 public ManProvider (string[] handbookTocFiles)
26 tocFiles = handbookTocFiles;
29 if (!File.Exists (tocFiles[0]))
30 throw new FileNotFoundException (String.Format ("The table of contents, `{0}' does not exist", tocFiles[0]));
33 public override void PopulateTree (Tree tree)
35 foreach(string TocFile in tocFiles) {
37 XmlDocument doc = new XmlDocument();
40 XmlNodeList nodeList = doc.GetElementsByTagName("manpage");
41 Node nodeToAddChildrenTo = tree;
43 foreach(XmlNode node in nodeList) {
45 XmlAttribute name = node.Attributes["name"];
46 XmlAttribute page = node.Attributes["page"];
48 if (name == null || page == null) continue;
50 if (!File.Exists (page.Value))
53 string target = "man:" + name.Value;
54 nodeToAddChildrenTo.CreateNode (name.Value, target);
56 if (File.Exists(page.Value))
57 nodeToAddChildrenTo.tree.HelpSource.PackFile (page.Value, name.Value);
63 public override void CloseTree (HelpSource hs, Tree tree)
69 // The HelpSource is used during the rendering phase.
72 public class ManHelpSource : HelpSource {
74 public ManHelpSource (string base_file, bool create) : base (base_file, create) {}
75 protected const string MAN_PREFIX = "man:";
77 public override string GetText (string url, out Node match_node)
80 if (url.IndexOf (MAN_PREFIX) > -1)
81 return GetTextFromUrl (url);
83 // display an index of sub-nodes.
84 StringBuilder buf = new StringBuilder ();
85 buf.Append ("<table bgcolor=\"#b0c4de\" width=\"100%\" cellpadding=\"5\"><tr><td><h3>Mono Documentation Library</h3></td></tr></table>");
86 buf.Append ("<p>Available man pages:</p>").Append ("<blockquote>");
87 foreach (Node n in Tree.Nodes) {
88 buf.Append ("<a href=\"").Append (n.Element).Append ("\">")
89 .Append (n.Caption).Append ("</a><br/>");
91 buf.Append ("</blockquote>");
92 return buf.ToString ();
98 protected string GetTextFromUrl (string url)
100 // Remove "man:" prefix including any help-source id on the front.
101 int prefixStart = url.IndexOf(MAN_PREFIX);
102 if (prefixStart > -1)
103 url = url.Substring (prefixStart + 4);
105 if (url == null || url.Length == 0)
107 Message (TraceLevel.Warning, "Warning, NULL url!");
108 return "<html>url was null</html>";
111 Stream stream = GetHelpStream (url);
112 return GetTextFromStream (stream);
115 public static string GetTextFromStream (Stream stream)
118 return "<html>url was null</html>";
119 StreamReader file = new StreamReader(stream);
122 StateInfo s = new StateInfo ();
124 while ((line = file.ReadLine ()) != null) {
125 ProcessLine (line, s);
127 return s.output.ToString ();
138 public Stack tags = new Stack ();
139 public StringBuilder output = new StringBuilder ();
142 private static void ProcessLine (string line, StateInfo s)
144 string[] parts = SplitLine (line);
146 case ".\\\"": // comments
147 case ".de": // define macro
150 case "..": // end macro
154 s.output.Append ("<i>");
155 Translate (parts, 1, s.output);
156 s.output.Append ("</i>");
159 s.output.Append ("<b>");
160 Translate (parts, 1, s.output);
161 s.output.Append ("</b>");
164 Translate (parts, 1, s.output);
165 s.output.Append ("<br />");
169 s.output.Append ("<pre>\n");
170 s.tags.Push ("</pre>");
173 Expect (s, "</pre>");
176 Expect (s, "</p>", "</dd>", "</dl>");
180 s.output.Append ("<p>");
181 Translate (parts, 1, s.output);
182 s.tags.Push ("</p>");
186 s.output.Append ("<blockquote>");
187 s.tags.Push ("</blockquote>");
190 ClearUntil (s, "</blockquote>");
194 s.output.Append ("<h2>");
195 Translate (parts, 1, s.output);
196 s.output.Append ("</h2>")
197 .Append ("<blockquote>");
198 s.tags.Push ("</blockquote>");
201 s.output.Append ("<h3>");
202 Translate (parts, 1, s.output);
203 s.output.Append ("</h3>");
207 string name = "", extra = "";
208 if (parts.Length >= 4 && parts [2].Trim ().Length == 0) {
209 name = parts [1] + "(" + parts [3] + ")";
210 if (parts.Length > 4) {
212 if (parts [start].Trim ().Length == 0)
214 extra = string.Join ("", parts, start, parts.Length-start);
218 name = string.Join ("", parts, 1, parts.Length-1);
219 s.output.Append ("<table width=\"100%\" bgcolor=\"#b0c4da\">" +
220 "<tr colspan=\"2\"><td>Manual Pages</td></tr>\n" +
222 Translate (name, s.output);
223 s.output.Append ("</h3></td><td align=\"right\">");
224 Translate (extra, s.output);
225 s.output.Append ("</td></tr></table>");
230 if (s.tags.Count > 0 && s.tags.Peek ().ToString () != "</dd>") {
231 s.output.Append ("<dl>");
232 s.tags.Push ("</dl>");
236 s.output.Append ("<dt>");
237 s.tags.Push ("</dt>");
238 s.ls = ListState.Start;
241 Translate (line, s.output);
244 if (s.ls == ListState.Start)
245 s.ls = ListState.Title;
246 else if (s.ls == ListState.Title) {
248 s.output.Append ("<dd>");
249 s.tags.Push ("</dd>");
250 s.ls = ListState.None;
252 s.output.Append ("\n");
255 private static string[] SplitLine (string line)
257 if (line.Length > 1 && line [0] != '.')
258 return new string[]{null, line};
261 for (i = 0; i < line.Length; ++i) {
262 if (char.IsWhiteSpace (line, i))
266 if (i == line.Length)
267 return new string[]{line};
269 ArrayList pieces = new ArrayList ();
270 pieces.Add (line.Substring (0, i));
271 bool inQuotes = false;
275 for ( ; i < line.Length; ++i) {
279 Add (pieces, line, start, i);
285 if (prevWs && c == '"') {
286 Add (pieces, line, start, i);
290 else if (char.IsWhiteSpace (c)) {
292 Add (pieces, line, start, i);
299 Add (pieces, line, start, i);
306 if (start > 0 && start != line.Length)
307 pieces.Add (line.Substring (start, line.Length-start));
308 return (string[]) pieces.ToArray (typeof(string));
311 private static void Add (ArrayList pieces, string line, int start, int end)
315 pieces.Add (line.Substring (start, end-start));
318 private static void Expect (StateInfo s, params string[] expected)
321 while (s.tags.Count > 0 &&
322 Array.IndexOf (expected, (e = s.tags.Peek ().ToString ())) >= 0) {
323 s.output.Append (s.tags.Pop ().ToString ());
327 private static void ClearUntil (StateInfo s, string required)
330 while (s.tags.Count > 0 &&
331 (e = s.tags.Peek ().ToString ()) != required) {
332 s.output.Append (s.tags.Pop ().ToString ());
335 s.output.Append (s.tags.Pop ().ToString ());
338 private static void ClearAll (StateInfo s)
340 while (s.tags.Count > 0)
341 s.output.Append (s.tags.Pop ().ToString ());
344 private static void Translate (string[] lines, int startIndex, StringBuilder output)
346 if (lines.Length <= startIndex)
349 Translate (lines [startIndex++], output);
350 if (startIndex == lines.Length)
352 } while (startIndex < lines.Length);
355 private static void Translate (string line, StringBuilder output)
358 int start = output.Length;
359 for (int i = 0; i < line.Length; ++i) {
362 if ((i+2) < line.Length && line [i+1] == 'f') {
363 if (line [i+2] == 'I') {
364 output.Append ("<i>");
367 else if (line [i+2] == 'B') {
368 output.Append ("<b>");
371 else if (line [i+2] == 'R' || line [i+2] == 'P') {
372 output.Append (span);
378 else if ((i+1) < line.Length) {
379 output.Append (line [i+1]);
387 output.Append ("<");
390 output.Append (">");
393 output.Append ("&");
396 output.Append (line [i]);