[mdoc-update] Support importing //returns & // value for "void" methods.
[mono.git] / mcs / tools / mdoc / Mono.Documentation / mdoc.cs
1 // Part of the mdoc(7) suite of tools.
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using Mono.Options;
9
10 namespace Mono.Documentation {
11
12         class MDoc {
13
14                 private static bool debug;
15
16                 private static void Main (string[] args)
17                 {
18                         MDoc d = new MDoc ();
19                         try {
20                                 d.Run (args);
21                         }
22                         catch (Exception e) {
23                                 if (debug) {
24                                         Console.Error.WriteLine ("mdoc: {0}", e.ToString ());
25                                 }
26                                 else {
27                                         Console.Error.WriteLine ("mdoc: {0}", e.Message);
28                                 }
29                                 Console.Error.WriteLine ("See `mdoc help' for more information.");
30                                 Environment.ExitCode = 1;
31                         }
32                 }
33
34                 int verbosity = 2;
35
36                 internal Dictionary<string, MDocCommand> subcommands;
37
38                 private void Run (string[] args)
39                 {
40                         subcommands = new Dictionary<string, MDocCommand> () {
41                                 { "assemble",         new MDocAssembler () },
42                                 { "dump-tree",        new MDocTreeDumper () },
43                                 { "export-html",      new MDocToHtmlConverter () },
44                                 { "export-html-webdoc",   new MDocExportWebdocHtml () },
45                                 { "export-msxdoc",    new MDocToMSXDocConverter () },
46                                 { "help",             new MDocHelpCommand (this) },
47                                 { "update",           new MDocUpdater () },
48                                 { "update-ecma-xml",  new MDocUpdateEcmaXml () },
49                                 { "validate",         new MDocValidator () },
50                         };
51
52                         bool showVersion = false;
53                         bool showHelp    = false;
54                         var extra = new List<string> ();
55                         var p = new OptionSet () {
56                                 { "version",  v => showVersion = v != null },
57                                 { "v:",       (int? v) => verbosity = v.HasValue ? v.Value : verbosity+1 },
58                                 { "debug",    v => debug = v != null },
59                                 { "h|?|help", v => showHelp = v != null },
60                                 { "<>",       v => { 
61                                                 if (v.Length > 0 && v [0] == '@')
62                                                         extra.AddRange (ReadResponseFile (v.Substring (1)));
63                                                 else
64                                                         extra.Add (v);
65                                 } },
66                         };
67
68                         p.Parse (args);
69
70                         if (showVersion) {
71                                 Console.WriteLine ("mdoc {0}", Consts.MonoVersion);
72                                 return;
73                         }
74                         if (extra.Count == 0) {
75                                 Console.WriteLine ("Use `mdoc help' for usage.");
76                                 return;
77                         }
78                         if (showHelp) {
79                                 extra.Add ("--help");
80                         }
81                         GetCommand (extra [0]).Run (extra);
82                 }
83
84                 // Cribbed from mcs/driver.cs:LoadArgs(string)
85                 static IEnumerable<string> ReadResponseFile (string file)
86                 {
87                         StreamReader response;
88                         try {
89                                 response = File.OpenText (file);
90                         } catch {
91                                 yield break;
92                         }
93
94                         using (response) {
95                                 StringBuilder arg = new StringBuilder ();
96
97                                 string line;
98                                 while ((line = response.ReadLine ()) != null) {
99                                         int t = line.Length;
100
101                                         for (int i = 0; i < t; i++) {
102                                                 char c = line [i];
103                                                 
104                                                 if (c == '"' || c == '\'') {
105                                                         char end = c;
106                                                         
107                                                         for (i++; i < t; i++){
108                                                                 c = line [i];
109
110                                                                 if (c == end)
111                                                                         break;
112                                                                 arg.Append (c);
113                                                         }
114                                                 } else if (c == ' ') {
115                                                         if (arg.Length > 0) {
116                                                                 yield return arg.ToString ();
117                                                                 arg.Length = 0;
118                                                         }
119                                                 } else
120                                                         arg.Append (c);
121                                         }
122                                         if (arg.Length > 0) {
123                                                 yield return arg.ToString ();
124                                                 arg.Length = 0;
125                                         }
126                                 }
127                         }
128                 }
129
130                 internal MDocCommand GetCommand (string command)
131                 {
132                         MDocCommand h;
133                         if (!subcommands.TryGetValue (command, out h)) {
134                                 Error ("Unknown command: {0}.", command);
135                         }
136                         h.TraceLevel  = (TraceLevel) verbosity;
137                         h.DebugOutput = debug;
138                         return h;
139                 }
140
141                 private static void Error (string format, params object[] args)
142                 {
143                         throw new Exception (string.Format (format, args));
144                 }
145         }
146
147         public abstract class MDocCommand {
148
149                 public TraceLevel TraceLevel { get; set; }
150                 public bool DebugOutput { get; set; }
151
152                 public abstract void Run (IEnumerable<string> args);
153
154                 protected List<string> Parse (OptionSet p, IEnumerable<string> args, 
155                                 string command, string prototype, string description)
156                 {
157                         bool showHelp = false;
158                         p.Add ("h|?|help", 
159                                         "Show this message and exit.", 
160                                         v => showHelp = v != null );
161
162                         List<string> extra = null;
163                         if (args != null) {
164                                 extra = p.Parse (args.Skip (1));
165                         }
166                         if (args == null || showHelp) {
167                                 Console.WriteLine ("usage: mdoc {0} {1}", 
168                                                 args == null ? command : args.First(), prototype);
169                                 Console.WriteLine ();
170                                 Console.WriteLine (description);
171                                 Console.WriteLine ();
172                                 Console.WriteLine ("Available Options:");
173                                 p.WriteOptionDescriptions (Console.Out);
174                                 return null;
175                         }
176                         return extra;
177                 }
178
179                 public void Error (string format, params object[] args)
180                 {
181                         throw new Exception (string.Format (format, args));
182                 }
183
184                 public void Message (TraceLevel level, string format, params object[] args)
185                 {
186                         if ((int) level > (int) TraceLevel)
187                                 return;
188                         if (level == TraceLevel.Error)
189                                 Console.Error.WriteLine (format, args);
190                         else
191                                 Console.WriteLine (format, args);
192                 }
193         }
194
195         class MDocHelpCommand : MDocCommand {
196
197                 MDoc instance;
198
199                 public MDocHelpCommand (MDoc instance)
200                 {
201                         this.instance = instance;
202                 }
203
204                 public override void Run (IEnumerable<string> args)
205                 {
206                         if (args != null && args.Count() > 1) {
207                                 foreach (var arg in args.Skip (1)) {
208                                         instance.GetCommand (arg).Run (new string[]{arg, "--help"});
209                                 }
210                                 return;
211                         }
212                         Message (TraceLevel.Warning, 
213                                 "usage: mdoc COMMAND [OPTIONS]\n" +
214                                 "Use `mdoc help COMMAND' for help on a specific command.\n" +
215                                 "\n" + 
216                                 "Available commands:\n\n   " +
217                                 string.Join ("\n   ", instance.subcommands.Keys.OrderBy (v => v).ToArray()) +
218                                 "\n\n" + 
219                                 "mdoc is a tool for documentation management.\n" +
220                                 "For additional information, see http://www.mono-project.com/"
221                         );
222                 }
223         }
224 }
225