PageRenderTime 31ms CodeModel.GetById 14ms app.highlight 12ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/tools/monodoc/Monodoc/man-provider.cs

https://github.com/sdether/mono
C# | 408 lines | 348 code | 42 blank | 18 comment | 86 complexity | ac0ac2b5dff1a9d17db3ffddcafb74a1 MD5 | raw file
  1//
  2// A provider to display man pages
  3//
  4// Authors:
  5//   Johannes Roith <johannes@roith.de>
  6//   Jonathan Pryor <jpryor@novell.com>
  7//
  8// (C) 2008 Novell, Inc.
  9
 10namespace Monodoc { 
 11using System;
 12using System.Collections;
 13using System.Diagnostics;
 14using System.IO;
 15using System.Text;
 16using System.Xml;
 17
 18//
 19// The simple provider generates the information source
 20//
 21public class ManProvider : Provider {
 22	string[] tocFiles;
 23	
 24	public  ManProvider (string[] handbookTocFiles)
 25	{
 26		tocFiles = handbookTocFiles;
 27
 28		// huh...
 29		if (!File.Exists (tocFiles[0]))
 30			throw new FileNotFoundException (String.Format ("The table of contents, `{0}' does not exist", tocFiles[0]));
 31	}
 32
 33	public override void PopulateTree (Tree tree)
 34	{
 35		foreach(string TocFile in tocFiles) {
 36
 37			XmlDocument doc = new XmlDocument();
 38			doc.Load(TocFile);
 39
 40			XmlNodeList nodeList = doc.GetElementsByTagName("manpage");
 41			Node nodeToAddChildrenTo = tree;
 42
 43			foreach(XmlNode node in nodeList) {
 44
 45				XmlAttribute name = node.Attributes["name"];
 46				XmlAttribute page = node.Attributes["page"];
 47
 48				if (name == null || page == null) continue;
 49
 50				if (!File.Exists (page.Value))
 51					continue;
 52
 53				string target = "man:" + name.Value;
 54				nodeToAddChildrenTo.CreateNode (name.Value, target);
 55
 56				if (File.Exists(page.Value))
 57					nodeToAddChildrenTo.tree.HelpSource.PackFile (page.Value, name.Value);
 58			}
 59		}
 60	}
 61
 62
 63	public override void CloseTree (HelpSource hs, Tree tree)
 64	{
 65	}
 66}
 67
 68//
 69// The HelpSource is used during the rendering phase.
 70//
 71
 72public class ManHelpSource : HelpSource {
 73	
 74	public ManHelpSource (string base_file, bool create) : base (base_file, create) {}
 75	protected const string MAN_PREFIX = "man:";
 76	
 77	public override string GetText (string url, out Node match_node)
 78	{
 79		match_node = null;
 80
 81		string c = GetCachedText (url);
 82		if (c != null)
 83			return c;
 84
 85		if (url.IndexOf (MAN_PREFIX) > -1)
 86			return GetTextFromUrl (url);
 87		if (url == "root:") {
 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/>");
 95			}
 96			buf.Append ("</blockquote>");
 97			return buf.ToString ();
 98		}
 99
100		return null;
101	}
102	
103	protected string GetTextFromUrl (string url)
104	{
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);
109
110		if (url == null || url.Length == 0)
111		{
112			Message (TraceLevel.Warning, "Warning, NULL url!");
113			return null;
114		}
115
116		Stream stream = GetHelpStream (url);
117		return GetTextFromStream (stream);
118	}
119
120	public static string GetTextFromStream (Stream stream)
121	{
122		if (stream == null)
123			return null;
124		StreamReader file = new StreamReader(stream);
125
126		string line;
127		StateInfo s = new StateInfo ();
128
129		while ((line = file.ReadLine ()) != null) {
130			ProcessLine (line, s);
131		}
132		return s.output.ToString ();
133	}
134
135	enum ListState {
136		None,
137		Start,
138		Title,
139	}
140
141	class StateInfo {
142		public ListState ls;
143		public Stack tags = new Stack ();
144		public StringBuilder output = new StringBuilder ();
145	}
146
147	private static void ProcessLine (string line, StateInfo s)
148	{
149		string[] parts = SplitLine (line);
150		switch (parts [0]) {
151			case ".\\\"": // comments
152			case ".de":   // define macro
153			case ".if":   // if
154			case ".ne":   // ???
155			case "..":    // end macro
156				// ignore
157				break;
158			case ".I":
159				s.output.Append ("<i>");
160				Translate (parts, 1, s.output);
161				s.output.Append ("</i>");
162				break;
163			case ".B":
164				s.output.Append ("<b>");
165				Translate (parts, 1, s.output);
166				s.output.Append ("</b>");
167				break;
168			case ".br":
169				Translate (parts, 1, s.output);
170				s.output.Append ("<br />");
171				break;
172			case ".nf":
173				Expect (s, "</p>");
174				s.output.Append ("<pre>\n");
175				s.tags.Push ("</pre>");
176				break;
177			case ".fi":
178				Expect (s, "</pre>");
179				break;
180			case ".PP":
181				Expect (s, "</p>", "</dd>", "</dl>");
182				goto case ".Sp";
183			case ".Sp":
184				Expect (s, "</p>");
185				s.output.Append ("<p>");
186				Translate (parts, 1, s.output);
187				s.tags.Push ("</p>");
188				break;
189			case ".RS":
190				Expect (s, "</p>");
191				s.output.Append ("<blockquote>");
192				s.tags.Push ("</blockquote>");
193				break;
194			case ".RE":
195				ClearUntil (s, "</blockquote>");
196				break;
197			case ".SH":
198				ClearAll (s);
199				s.output.Append ("<h2>");
200				Translate (parts, 1, s.output);
201				s.output.Append ("</h2>")
202					.Append ("<blockquote>");
203				s.tags.Push ("</blockquote>");
204				break;
205			case ".SS":
206				s.output.Append ("<h3>");
207				Translate (parts, 1, s.output);
208				s.output.Append ("</h3>");
209				break;
210			case ".TH": {
211				ClearAll (s);
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) {
216						int start = 4;
217						if (parts [start].Trim ().Length == 0)
218							++start;
219						extra = string.Join ("", parts, start, parts.Length-start);
220					}
221				}
222				else
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" +
226						"<tr><td><h3>");
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>");
231				break;
232			}
233			case ".TP":
234				Expect (s, "</p>");
235				if (s.tags.Count > 0 && s.tags.Peek ().ToString () != "</dd>") {
236					s.output.Append ("<dl>");
237					s.tags.Push ("</dl>");
238				}
239				else
240					Expect (s, "</dd>");
241				s.output.Append ("<dt>");
242				s.tags.Push ("</dt>");
243				s.ls = ListState.Start;
244				break;
245			default:
246				Translate (line, s.output);
247				break;
248		}
249		if (s.ls == ListState.Start)
250			s.ls = ListState.Title;
251		else if (s.ls == ListState.Title) {
252			Expect (s, "</dt>");
253			s.output.Append ("<dd>");
254			s.tags.Push ("</dd>");
255			s.ls = ListState.None;
256		}
257		s.output.Append ("\n");
258	}
259
260	private static string[] SplitLine (string line)
261	{
262		if (line.Length > 1 && line [0] != '.')
263			return new string[]{null, line};
264
265		int i;
266		for (i = 0; i < line.Length; ++i) {
267			if (char.IsWhiteSpace (line, i))
268				break;
269		}
270
271		if (i == line.Length)
272			return new string[]{line};
273
274		ArrayList pieces = new ArrayList ();
275		pieces.Add (line.Substring (0, i));
276		bool inQuotes = false;
277		bool prevWs   = true;
278		++i;
279		int start = i;
280		for ( ; i < line.Length; ++i) {
281			char c = line [i];
282			if (inQuotes) {
283				if (c == '"') {
284					Add (pieces, line, start, i);
285					start = i+1;
286					inQuotes = false;
287				}
288			}
289			else {
290				if (prevWs && c == '"') {
291					Add (pieces, line, start, i);
292					start = i+1;
293					inQuotes = true;
294				}
295				else if (char.IsWhiteSpace (c)) {
296					if (!prevWs) {
297						Add (pieces, line, start, i);
298						start = i;
299					}
300					prevWs = true;
301				}
302				else {
303					if (prevWs) {
304						Add (pieces, line, start, i);
305						start = i;
306					}
307					prevWs = false;
308				}
309			}
310		}
311		if (start > 0 && start != line.Length)
312			pieces.Add (line.Substring (start, line.Length-start));
313		return (string[]) pieces.ToArray (typeof(string));
314	}
315
316	private static void Add (ArrayList pieces, string line, int start, int end)
317	{
318		if (start == end)
319			return;
320		pieces.Add (line.Substring (start, end-start));
321	}
322
323	private static void Expect (StateInfo s, params string[] expected)
324	{
325		string e;
326		while (s.tags.Count > 0 && 
327				Array.IndexOf (expected, (e = s.tags.Peek ().ToString ())) >= 0) {
328			s.output.Append (s.tags.Pop ().ToString ());
329		}
330	}
331
332	private static void ClearUntil (StateInfo s, string required)
333	{
334		string e;
335		while (s.tags.Count > 0 && 
336				(e = s.tags.Peek ().ToString ()) != required) {
337			s.output.Append (s.tags.Pop ().ToString ());
338		}
339		if (e == required)
340			s.output.Append (s.tags.Pop ().ToString ());
341	}
342
343	private static void ClearAll (StateInfo s)
344	{
345		while (s.tags.Count > 0)
346			s.output.Append (s.tags.Pop ().ToString ());
347	}
348
349	private static void Translate (string[] lines, int startIndex, StringBuilder output)
350	{
351		if (lines.Length <= startIndex)
352			return;
353		do {
354			Translate (lines [startIndex++], output);
355			if (startIndex == lines.Length)
356				break;
357		} while (startIndex < lines.Length);
358	}
359
360	private static void Translate (string line, StringBuilder output)
361	{
362		string span = null;
363		int start = output.Length;
364		for (int i = 0; i < line.Length; ++i) {
365			switch (line [i]) {
366				case '\\': {
367					if ((i+2) < line.Length && line [i+1] == 'f') {
368						if (line [i+2] == 'I') {
369							output.Append ("<i>");
370							span = "</i>";
371						}
372						else if (line [i+2] == 'B') {
373							output.Append ("<b>");
374							span = "</b>";
375						}
376						else if (line [i+2] == 'R' || line [i+2] == 'P') {
377							output.Append (span);
378						}
379						else
380							goto default;
381						i += 2;
382					}
383					else if ((i+1) < line.Length) {
384						output.Append (line [i+1]);
385						++i;
386					}
387					else
388						goto default;
389					break;
390				}
391				case '<':
392					output.Append ("&lt;");
393					break;
394				case '>':
395					output.Append ("&gt;");
396					break;
397				case '&':
398					output.Append ("&amp;");
399					break;
400				default:
401					output.Append (line [i]);
402					break;
403			}
404		}
405	}
406}
407
408}