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)
81 string c = GetCachedText (url);
85 if (url.IndexOf (MAN_PREFIX) > -1)
86 return GetTextFromUrl (url);
88 // display an index of sub-nodes.
89 StringBuilder buf = new StringBuilder ();
90 buf.Append ("<table bgcolor=\"#b0c4de\" width=\"100%\" cellpadding=\"5\"><tr><td><h3>Mono Documentation Library</h3></td></tr></table>");
91 buf.Append ("<p>Available man pages:</p>").Append ("<blockquote>");
92 foreach (Node n in Tree.Nodes) {
93 buf.Append ("<a href=\"").Append (n.Element).Append ("\">")
94 .Append (n.Caption).Append ("</a><br/>");
96 buf.Append ("</blockquote>");
97 return buf.ToString ();
103 protected string GetTextFromUrl (string url)
105 // Remove "man:" prefix including any help-source id on the front.
106 int prefixStart = url.IndexOf(MAN_PREFIX);
107 if (prefixStart > -1)
108 url = url.Substring (prefixStart + 4);
110 if (url == null || url.Length == 0)
112 Message (TraceLevel.Warning, "Warning, NULL url!");
116 Stream stream = GetHelpStream (url);
117 return GetTextFromStream (stream);
120 public static string GetTextFromStream (Stream stream)
124 StreamReader file = new StreamReader(stream);
127 StateInfo s = new StateInfo ();
129 while ((line = file.ReadLine ()) != null) {
130 ProcessLine (line, s);
132 return s.output.ToString ();
143 public Stack tags = new Stack ();
144 public StringBuilder output = new StringBuilder ();
147 private static void ProcessLine (string line, StateInfo s)
149 string[] parts = SplitLine (line);
151 case ".\\\"": // comments
152 case ".de": // define macro
155 case "..": // end macro
159 s.output.Append ("<i>");
160 Translate (parts, 1, s.output);
161 s.output.Append ("</i>");
164 s.output.Append ("<b>");
165 Translate (parts, 1, s.output);
166 s.output.Append ("</b>");
169 Translate (parts, 1, s.output);
170 s.output.Append ("<br />");
174 s.output.Append ("<pre>\n");
175 s.tags.Push ("</pre>");
178 Expect (s, "</pre>");
181 Expect (s, "</p>", "</dd>", "</dl>");
185 s.output.Append ("<p>");
186 Translate (parts, 1, s.output);
187 s.tags.Push ("</p>");
191 s.output.Append ("<blockquote>");
192 s.tags.Push ("</blockquote>");
195 ClearUntil (s, "</blockquote>");
199 s.output.Append ("<h2>");
200 Translate (parts, 1, s.output);
201 s.output.Append ("</h2>")
202 .Append ("<blockquote>");
203 s.tags.Push ("</blockquote>");
206 s.output.Append ("<h3>");
207 Translate (parts, 1, s.output);
208 s.output.Append ("</h3>");
212 string name = "", extra = "";
213 if (parts.Length >= 4 && parts [2].Trim ().Length == 0) {
214 name = parts [1] + "(" + parts [3] + ")";
215 if (parts.Length > 4) {
217 if (parts [start].Trim ().Length == 0)
219 extra = string.Join ("", parts, start, parts.Length-start);
223 name = string.Join ("", parts, 1, parts.Length-1);
224 s.output.Append ("<table width=\"100%\" bgcolor=\"#b0c4da\">" +
225 "<tr colspan=\"2\"><td>Manual Pages</td></tr>\n" +
227 Translate (name, s.output);
228 s.output.Append ("</h3></td><td align=\"right\">");
229 Translate (extra, s.output);
230 s.output.Append ("</td></tr></table>");
235 if (s.tags.Count > 0 && s.tags.Peek ().ToString () != "</dd>") {
236 s.output.Append ("<dl>");
237 s.tags.Push ("</dl>");
241 s.output.Append ("<dt>");
242 s.tags.Push ("</dt>");
243 s.ls = ListState.Start;
246 Translate (line, s.output);
249 if (s.ls == ListState.Start)
250 s.ls = ListState.Title;
251 else if (s.ls == ListState.Title) {
253 s.output.Append ("<dd>");
254 s.tags.Push ("</dd>");
255 s.ls = ListState.None;
257 s.output.Append ("\n");
260 private static string[] SplitLine (string line)
262 if (line.Length > 1 && line [0] != '.')
263 return new string[]{null, line};
266 for (i = 0; i < line.Length; ++i) {
267 if (char.IsWhiteSpace (line, i))
271 if (i == line.Length)
272 return new string[]{line};
274 ArrayList pieces = new ArrayList ();
275 pieces.Add (line.Substring (0, i));
276 bool inQuotes = false;
280 for ( ; i < line.Length; ++i) {
284 Add (pieces, line, start, i);
290 if (prevWs && c == '"') {
291 Add (pieces, line, start, i);
295 else if (char.IsWhiteSpace (c)) {
297 Add (pieces, line, start, i);
304 Add (pieces, line, start, i);
311 if (start > 0 && start != line.Length)
312 pieces.Add (line.Substring (start, line.Length-start));
313 return (string[]) pieces.ToArray (typeof(string));
316 private static void Add (ArrayList pieces, string line, int start, int end)
320 pieces.Add (line.Substring (start, end-start));
323 private static void Expect (StateInfo s, params string[] expected)
326 while (s.tags.Count > 0 &&
327 Array.IndexOf (expected, (e = s.tags.Peek ().ToString ())) >= 0) {
328 s.output.Append (s.tags.Pop ().ToString ());
332 private static void ClearUntil (StateInfo s, string required)
335 while (s.tags.Count > 0 &&
336 (e = s.tags.Peek ().ToString ()) != required) {
337 s.output.Append (s.tags.Pop ().ToString ());
340 s.output.Append (s.tags.Pop ().ToString ());
343 private static void ClearAll (StateInfo s)
345 while (s.tags.Count > 0)
346 s.output.Append (s.tags.Pop ().ToString ());
349 private static void Translate (string[] lines, int startIndex, StringBuilder output)
351 if (lines.Length <= startIndex)
354 Translate (lines [startIndex++], output);
355 if (startIndex == lines.Length)
357 } while (startIndex < lines.Length);
360 private static void Translate (string line, StringBuilder output)
363 int start = output.Length;
364 for (int i = 0; i < line.Length; ++i) {
367 if ((i+2) < line.Length && line [i+1] == 'f') {
368 if (line [i+2] == 'I') {
369 output.Append ("<i>");
372 else if (line [i+2] == 'B') {
373 output.Append ("<b>");
376 else if (line [i+2] == 'R' || line [i+2] == 'P') {
377 output.Append (span);
383 else if ((i+1) < line.Length) {
384 output.Append (line [i+1]);
392 output.Append ("<");
395 output.Append (">");
398 output.Append ("&");
401 output.Append (line [i]);