3 // Adam Treat (manyoso@yahoo.com)
7 // Licensed under the terms of the GNU GPL
10 using System.Reflection;
11 using System.Collections;
24 string output_file, assembly_file, directory;
29 "docstub (-d <directory> || -o <file>) -a <assembly>\n\n" +
30 " -d || --dir <directory> The directory to write the xml files to.\n" +
31 " -o || --output <file> Specifies that docstub should write to one large output file.\n" +
32 " -a || --assembly <assembly> Specifies the target assembly to load and parse.\n\n");
35 public static void Main(string[] args)
37 DocStub stub = new DocStub(args);
40 public DocStub(string [] args)
45 int argc = args.Length;
47 for(int i = 0; i < argc; i++)
51 // The "/" switch is there for wine users, like me ;-)
52 if(arg.StartsWith("-") || arg.StartsWith("/"))
57 case "-d": case "/-d": case "--directory":
63 directory = args[++i];
66 case "-o": case "/-o": case "--output":
72 output_file = args[++i];
75 case "-a": case "/-a": case "--assembly":
81 assembly_file = args[++i];
91 if(assembly_file == null)
95 } else if(directory == null && output_file == null)
101 if(directory != null)
103 // This specifies that writing to a directory is the default behavior
104 // If someone attempts to write to both a directory and an output file
105 // Only the directory will be written to...
109 if (!Directory.Exists(directory) && directory != null)
111 Directory.CreateDirectory(directory);
114 // Call the main driver to get some things done
119 // This method loads the assembly and generates a types list
120 // It also takes care of the end product, ie writing the xml
121 // to the given filename, or filenames...
125 Type[] assemblyTypes;
126 Assembly assembly = null;
127 ArrayList TypesList = new ArrayList();
129 assembly = LoadAssembly(Path.GetFullPath(assembly_file));
131 // GetTypes() doesn't seem to like loading some dll's, but then
132 // the exception holds all the types in the dll anyway, some
133 // are in Types and some are in the LoaderExceptions array.
136 assemblyTypes = assembly.GetTypes();
138 catch(ReflectionTypeLoadException e)
140 assemblyTypes = e.Types;
141 foreach(TypeLoadException loadException in e.LoaderExceptions)
143 TypesList.Add(loadException.TypeName);
147 // Create an xml document to check the output [debugging purposes]
148 //xmldoc = new XmlDocument();
149 //xmldoc.PreserveWhitespace = true;
152 // GenerateXML will take care of converting all the Types info
153 // into XML and return a string for writing out to file, files
155 if(output_file != null)
157 writer = new XmlTextWriter (output_file, null);
158 writer.Formatting = Formatting.Indented;
159 writer.WriteStartDocument();
160 writer.WriteDocType("MonoDocStub", null, null, null);
161 writer.WriteStartElement("assembly");
163 foreach(Type name in assemblyTypes)
171 writer.WriteEndElement();
172 writer.WriteEndDocument();
175 // Load the file and check it is wellformed [debugging purposes]
176 //xmldoc.Load(output_file);
179 else if (directory != null)
181 foreach(Type name in assemblyTypes)
185 string filename = directory+"/"+name+".xml";
186 writer = new XmlTextWriter (filename, null);
187 writer.Formatting = Formatting.Indented;
188 writer.WriteStartDocument();
189 writer.WriteDocType("MonoDocStub", null, null, null);
190 writer.WriteStartElement("assembly");
192 writer.WriteEndElement();
193 writer.WriteEndDocument();
196 // Load the file and check it is wellformed [debugging purposes]
197 //xmldoc.Load(filename);
204 // This method loads an assembly into memory. If you
205 // use Assembly.Load or Assembly.LoadFrom the assembly file locks.
206 // This method doesn't lock the assembly file.
207 Assembly LoadAssembly(string filename)
211 FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read);
212 byte[] buffer = new byte[fs.Length];
213 fs.Read(buffer, 0, (int)fs.Length);
216 return Assembly.Load(buffer);
218 catch(FileNotFoundException)
220 Console.WriteLine("Could not find assembly file: {0}", assembly_file);
226 // The main xml generation method!
228 void GenerateXML(Type name)
233 //This is what the try block is for
234 members = currentType.GetMembers();
235 // This is where we generate xml for the class/type
236 writer.WriteStartElement("class");
237 writer.WriteStartElement("name");
238 writer.WriteString(currentType.FullName);
239 writer.WriteEndElement();
242 // Generate xml for members (constructors, fields, methods etc)
243 if(members.Length > 0)
245 foreach(MemberInfo m in members)
247 if (m is ConstructorInfo)
249 writer.WriteStartElement("member");
250 writer.WriteStartElement("name");
251 writer.WriteString(currentType.Name);
252 writer.WriteEndElement();
253 writer.WriteStartElement("type");
254 writer.WriteString("constructor");
255 writer.WriteEndElement();
256 getConstructorXml((ConstructorInfo)m);
257 writer.WriteEndElement();
259 else if (m is EventInfo)
261 writer.WriteStartElement("member");
262 writer.WriteStartElement("name");
263 writer.WriteString(m.Name);
264 writer.WriteEndElement();
265 writer.WriteStartElement("type");
266 writer.WriteString("event");
267 writer.WriteEndElement();
268 getEventXml((EventInfo)m);
269 writer.WriteEndElement();
271 else if (m is FieldInfo)
273 writer.WriteStartElement("member");
274 writer.WriteStartElement("name");
275 writer.WriteString(m.Name);
276 writer.WriteEndElement();
277 writer.WriteStartElement("type");
278 writer.WriteString("field");
279 writer.WriteEndElement();
280 getFieldXml((FieldInfo)m);
281 writer.WriteEndElement();
283 else if (m is PropertyInfo)
285 writer.WriteStartElement("member");
286 writer.WriteStartElement("name");
287 writer.WriteString(m.Name);
288 writer.WriteEndElement();
289 writer.WriteStartElement("type");
290 writer.WriteString("property");
291 writer.WriteEndElement();
292 getPropertyXml((PropertyInfo)m);
293 writer.WriteEndElement();
295 else if (m is MethodInfo)
297 writer.WriteStartElement("member");
298 writer.WriteStartElement("name");
299 writer.WriteString(m.Name);
300 writer.WriteEndElement();
301 writer.WriteStartElement("type");
302 writer.WriteString("method");
303 writer.WriteEndElement();
304 getMethodXml((MethodInfo)m);
305 writer.WriteEndElement();
310 // Don't forget to close the xml ;-)
311 writer.WriteEndElement();
313 catch(TypeLoadException e)
315 // Todo Mono's corlib keeps failing here because System.Object
316 // Doesn't have any parents
317 Console.WriteLine("Class: "+e.TypeName+" has caused a TypeLoad Exception."
318 +" No XML will be generated for this type.");
323 // This just calls the methods for elements within a constructor
325 void getConstructorXml(ConstructorInfo construct)
327 getMethodBaseInfoXml(construct);
328 getParameterInfoXml(construct);
329 getInheritInfoXml(construct);
333 // Calls the methods for elements within an event member
335 void getEventXml(EventInfo eve)
337 getEventInfoXml(eve);
338 getInheritInfoXml(eve);
342 // Calls the methods for xml elements within a field
344 void getFieldXml(FieldInfo field)
346 writer.WriteStartElement("field_type");
347 writer.WriteString(field.FieldType.Name);
348 writer.WriteEndElement();
349 getFieldInfoXml(field);
350 getInheritInfoXml(field);
354 // Calls the methods for xml elements within a property
356 void getPropertyXml(PropertyInfo property)
358 writer.WriteStartElement("property_type");
359 writer.WriteString(property.PropertyType.Name);
360 writer.WriteEndElement();
361 getPropertyInfoXml(property);
362 getInheritInfoXml(property);
366 // Calls the methods for xml elements within a method
368 void getMethodXml(MethodInfo method)
370 getMethodBaseInfoXml(method);
371 getParameterInfoXml(method);
372 getReturnInfoXml(method);
373 getInheritInfoXml(method);
377 // Probably should just go in the getMethodXml, but here for asthetic reasons ;-)
379 void getReturnInfoXml(MethodInfo method)
383 writer.WriteStartElement("return");
384 writer.WriteString(method.ReturnType.Name);
385 writer.WriteEndElement();
389 // Mysteriously this is also causing some corlib types
390 // to spit out some Object doesn't have a parent errors
391 //Console.WriteLine(e.Message);
392 writer.WriteEndElement();
397 // Checks to see if a member is inherited and output xml
399 void getInheritInfoXml(MemberInfo member)
401 if(member.DeclaringType != currentType)
403 writer.WriteStartElement("inherit");
404 writer.WriteString(member.DeclaringType.Name);
405 writer.WriteEndElement();
406 writer.WriteStartElement("inheritfull");
407 writer.WriteString(member.DeclaringType.FullName);
408 writer.WriteEndElement();
413 // Checks for get or set in properties
415 void getPropertyInfoXml(PropertyInfo property)
419 writer.WriteStartElement("attribute");
420 writer.WriteString("get");
421 writer.WriteEndElement();
423 if(property.CanWrite)
425 writer.WriteStartElement("attribute");
426 writer.WriteString("set");
427 writer.WriteEndElement();
434 void getParameterInfoXml(MethodBase method)
438 ParameterInfo[] parameters = method.GetParameters();
439 if(parameters.Length != 0)
441 foreach(ParameterInfo p in parameters)
443 writer.WriteStartElement("param");
444 writer.WriteStartElement("name");
445 writer.WriteString(p.Name);
446 writer.WriteEndElement();
447 writer.WriteStartElement("type");
448 writer.WriteString(p.ParameterType.Name);
449 writer.WriteEndElement();
450 if(p.DefaultValue != DBNull.Value)
452 writer.WriteStartElement("default");
453 writer.WriteString(p.DefaultValue.ToString());
454 writer.WriteEndElement();
456 writer.WriteStartElement("position");
457 writer.WriteString(p.Position.ToString());
458 writer.WriteEndElement();
459 writer.WriteEndElement();
465 // Mysteriously this is also causing some corlib types
466 // to spit out some Object doesn't have a parent errors
467 //Console.WriteLine(e.Message);
472 // Find Attributes for events
474 void getEventInfoXml(EventInfo _obj)
478 writer.WriteStartElement("attribute");
479 writer.WriteString("multicast");
480 writer.WriteEndElement();
482 writer.WriteStartElement("eventhandler");
483 writer.WriteString(_obj.EventHandlerType.Name);
484 writer.WriteEndElement();
488 // Find Attributes for fields
490 void getFieldInfoXml(FieldInfo _obj)
494 writer.WriteStartElement("attribute");
495 writer.WriteString("private");
496 writer.WriteEndElement();
501 writer.WriteStartElement("attribute");
502 writer.WriteString("public");
503 writer.WriteEndElement();
508 writer.WriteStartElement("attribute");
509 writer.WriteString("static");
510 writer.WriteEndElement();
515 // Find Attributes for constructors and methods
517 void getMethodBaseInfoXml(MethodBase _obj)
522 writer.WriteStartElement("attribute");
523 writer.WriteString("abstract");
524 writer.WriteEndElement();
529 writer.WriteStartElement("attribute");
530 writer.WriteString("final");
531 writer.WriteEndElement();
536 writer.WriteStartElement("attribute");
537 writer.WriteString("private");
538 writer.WriteEndElement();
543 writer.WriteStartElement("attribute");
544 writer.WriteString("public");
545 writer.WriteEndElement();
550 writer.WriteStartElement("attribute");
551 writer.WriteString("static");
552 writer.WriteEndElement();
557 writer.WriteStartElement("attribute");
558 writer.WriteString("virtual");
559 writer.WriteEndElement();
564 // Put this at the end because it's ugly, but gets the job done
566 void getTypeInfoXml()
570 writer.WriteStartElement("inherit");
571 writer.WriteString(currentType.BaseType.Name);
572 writer.WriteEndElement();
573 writer.WriteStartElement("inheritfull");
574 writer.WriteString(currentType.BaseType.FullName);
575 writer.WriteEndElement();
577 if(currentType.IsAbstract)
579 writer.WriteStartElement("attribute");
580 writer.WriteString("abstract");
581 writer.WriteEndElement();
584 if(currentType.IsEnum)
586 writer.WriteStartElement("attribute");
587 writer.WriteString("enum");
588 writer.WriteEndElement();
591 if(currentType.IsInterface)
593 writer.WriteStartElement("attribute");
594 writer.WriteString("interface");
595 writer.WriteEndElement();
598 if(currentType.IsPrimitive)
600 writer.WriteStartElement("attribute");
601 writer.WriteString("primitive");
602 writer.WriteEndElement();
605 if(currentType.IsPublic)
607 writer.WriteStartElement("attribute");
608 writer.WriteString("public");
609 writer.WriteEndElement();
612 if(currentType.IsSealed)
614 writer.WriteStartElement("attribute");
615 writer.WriteString("sealed");
616 writer.WriteEndElement();
619 if(currentType.IsSerializable)
621 writer.WriteStartElement("attribute");
622 writer.WriteString("serializable");
623 writer.WriteEndElement();
628 Console.WriteLine("A Class has caused an Exception."
629 +" This occurred whilst trying to retrieve said types inheritable information.");
630 writer.WriteEndElement();