Must anything in particular be done to add a new tool to the mcs/tools
directory?

I've been working on a reflection tool which would display most of the
information available through System.Type for a given type.  I call it
`type-reflector', and it's attached.

To use it, just specify the type to view on the command line with the
`-S' (show all) and `-v' (verbose) options specified.

It currently doesn't display *all* System.Type information due to
deficiencies with Mono.  Some reflection attributes aren't present in
Mono (such as Assembly.EscapedCodeBase), while others generate run-time
exceptions when invoked (Assembly.ToString() is currently giving me
problems).  All information available through the public Attributes of
the System.Type and related classes can be viewed by compiling with "-D
MONO_BROKEN" and executing with `-K' (show broKen attributes).

It also provides a simple way to view the values of enumeration
constants.  (I was never able to make `EnumCheck.exe' work, so this
provides an alternative.)  For an example, run the program as:

        mono type-reflector.exe -Afv type-reflector.exe TestEnum

and look for "Enumeration Value" in the output.

Thanks,
 - Jon

//
// type-reflector.cs: 
//   Finds types and (optionally) shows reflection information about 
//   the types.
//
// Author: Jonathan Pryor ([EMAIL PROTECTED])
//
// (C) 2002 Jonathan Pryor
//
// Permission is hereby granted, free of charge, to any           
// person obtaining a copy of this software and associated        
// documentation files (the "Software"), to deal in the           
// Software without restriction, including without limitation     
// the rights to use, copy, modify, merge, publish,               
// distribute, sublicense, and/or sell copies of the Software,    
// and to permit persons to whom the Software is furnished to     
// do so, subject to the following conditions:                    
//                                                                 
// The above copyright notice and this permission notice          
// shall be included in all copies or substantial portions        
// of the Software.                                               
//                                                                 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY      
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO         
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A               
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL      
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,      
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION       
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// #define TRACE

using System;
using System.Collections;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace Testing
{
        interface IFoo {}
        interface IBar {}
        interface IBaz {}

        delegate void FooEventHandler ();

        [CLSCompliant(false)]
        class TestClass : IFoo, IBar, IBaz {
                private int PrivateField;
                protected float ProtectedField;
                public double PublicField;
                internal long InternalField;

                public TestClass (short s) {PublicField = 3.14;}
                protected TestClass (long l) {ProtectedField = 2.71F;}
                private TestClass (int i) {PrivateField = 13;}
                internal TestClass (float f) {InternalField = 64;}

                public int PublicGetSet {
                        get {return 0;}
                        set {PublicField = value;}
                }

                protected short ProtectedGetter {
                        get {return -1;}
                }

                private char PrivateSetter {
                        set {PrivateField = value;}
                }

                internal float InternalProperty {
                        get {return ProtectedField;}
                        set {ProtectedField = value;}
                }

                public event FooEventHandler PubFoo;
                protected event FooEventHandler ProFoo;
                private event FooEventHandler PrivFoo;
                internal event FooEventHandler IntFoo;

                public short PublicMethod (short s) {return s;}
                private int PrivateMethod (int i) {return i;}
                protected long ProtectedMethod (long l) {return l;}
                internal float InternalMethod (float f) {return f;}
        }

        enum TestEnum {
                Foo, 
                Bar, 
                Baz, 
                Qux, 
                Quux
        }
}

namespace Mono.TypeReflector
{
        public delegate void BaseTypeEventHandler (object sender, BaseTypeEventArgs e);
        public delegate void TypeEventHandler (object sender, TypeEventArgs e);
        public delegate void InterfacesEventHandler (object sender, 
InterfacesEventArgs e);
        public delegate void FieldsEventHandler (object sender, FieldsEventArgs e);
        public delegate void PropertiesEventHandler (object sender, 
PropertiesEventArgs e);
        public delegate void EventsEventHandler (object sender, EventsEventArgs e);
        public delegate void ConstructorsEventHandler (object sender, 
ConstructorsEventArgs e);
        public delegate void MethodsEventHandler (object sender, MethodsEventArgs e);

        public class BaseTypeEventArgs : EventArgs {

                private Type _base;

                internal BaseTypeEventArgs (Type type)
                {
                        _base = type;
                }

                public Type BaseType {
                        get {return _base;}
                }
        }

        public class TypeEventArgs : EventArgs {

                private Type _type;

                internal TypeEventArgs (Type type)
                {
                        _type = type;
                }

                public Type Type {
                        get {return _type;}
                }
        }

        public class InterfacesEventArgs : EventArgs {

                private Type[] _interfaces;

                internal InterfacesEventArgs (Type[] interfaces)
                {
                        _interfaces = interfaces ;
                }

                public Type[] Interfaces {
                        get {return _interfaces;}
                }
        }

        public class FieldsEventArgs : EventArgs {
                private FieldInfo[] _fields;

                internal FieldsEventArgs (FieldInfo[] fields)
                {
                        _fields = fields;
                }

                public FieldInfo[] Fields {
                        get {return _fields;}
                }
        }

        public class PropertiesEventArgs : EventArgs {

                private PropertyInfo[] _props;

                internal PropertiesEventArgs (PropertyInfo[] properties)
                {
                        _props = properties;
                }

                public PropertyInfo[] Properties {
                        get {return _props;}
                }
        }

        public class EventsEventArgs : EventArgs {

                private EventInfo[] _events;

                internal EventsEventArgs (EventInfo[] events)
                {
                        _events = events;
                }

                public EventInfo[] Events {
                        get {return _events;}
                }
        }

        public class ConstructorsEventArgs : EventArgs {

                private ConstructorInfo[] _ctors;

                internal ConstructorsEventArgs (ConstructorInfo[] ctors)
                {
                        _ctors = ctors;
                }

                public ConstructorInfo[] Constructors {
                        get {return _ctors;}
                }
        }

        public class MethodsEventArgs : EventArgs {

                private MethodInfo[] _methods;

                internal MethodsEventArgs (MethodInfo[] methods)
                {
                        _methods = methods;
                }

                public MethodInfo[] Methods {
                        get {return _methods;}
                }
        }

        public class TypeDisplayer {

                private bool showBase = false;
                private bool showConstructors = false;
                private bool showEvents = false;
                private bool showFields = false;
                private bool showInterfaces = false;
                private bool showMethods = false;
                private bool showProperties = false;
                private bool showTypeProperties = false;
                private bool showInheritedMembers = false;
                private bool verboseOutput = false;
                private bool flattenHierarchy = false;
                private bool showNonPublic = false;
                private bool showMonoBroken = false;

                public bool ShowBase {
                        get {return showBase;}
                        set {showBase = value;}
                }

                public bool ShowConstructors {
                        get {return showConstructors;}
                        set {showConstructors = value;}
                }

                public bool ShowEvents {
                        get {return showEvents;}
                        set {showEvents = value;}
                }

                public bool ShowFields {
                        get {return showFields;}
                        set {showFields = value;}
                }

                public bool ShowInterfaces {
                        get {return showInterfaces;}
                        set {showInterfaces = value;}
                }

                public bool ShowMethods {
                        get {return showMethods;}
                        set {showMethods = value;}
                }

                public bool ShowProperties {
                        get {return showProperties;}
                        set {showProperties = value;}
                }

                public bool ShowTypeProperties {
                        get {return showTypeProperties;}
                        set {showTypeProperties = value;}
                }

                public bool ShowInheritedMembers {
                        get {return showInheritedMembers;}
                        set {showInheritedMembers = value;}
                }

                public bool ShowNonPublic {
                        get {return showNonPublic;}
                        set {showNonPublic = value;}
                }

                public bool ShowMonoBroken {
                        get {return showMonoBroken;}
                        set {showMonoBroken = value;}
                }

                public bool FlattenHierarchy {
                        get {return flattenHierarchy;}
                        set {flattenHierarchy = value;}
                }

                public bool VerboseOutput {
                        get {return verboseOutput;}
                        set {verboseOutput = value;}
                }

                private static BindingFlags bindingFlags = 
                        BindingFlags.DeclaredOnly | 
                        BindingFlags.Public | 
                        BindingFlags.Instance | 
                        BindingFlags.Static;

                public void Parse (Type type)
                {
                        BindingFlags bf = bindingFlags;

                        if (FlattenHierarchy)
                                bf |= BindingFlags.FlattenHierarchy;
                        if (ShowInheritedMembers)
                                bf &= ~BindingFlags.DeclaredOnly;
                        if (ShowNonPublic)
                                bf |= BindingFlags.NonPublic;

                        Type (type);

                        BaseType (type.BaseType);
                        Interfaces (type.GetInterfaces ());
                        Fields (type.GetFields(bf));
                        Constructors (type.GetConstructors(bf));
                        Properties (type.GetProperties(bf));
                        Events (type.GetEvents(bf));
                        Methods (type.GetMethods(bf));
                }

                private void Type (Type t)
                {
                        TypeEventArgs ea = new TypeEventArgs (t);
                        try {
                                OnType (ea);
                        } finally {
                                if (ReceiveTypes != null)
                                        ReceiveTypes (this, ea);
                        }
                }

                protected virtual void OnType (TypeEventArgs e) {}

                private void BaseType (Type t)
                {
                        if (ShowBase) {
                                BaseTypeEventArgs ea = new BaseTypeEventArgs (t);
                                try {
                                        OnBaseType (ea);
                                } finally {
                                        if (ReceiveBaseType != null)
                                                ReceiveBaseType (this, ea);
                                }
                        }
                }

                protected virtual void OnBaseType (BaseTypeEventArgs e) {}

                private void Interfaces (Type[] i)
                {
                        if (ShowInterfaces) {
                                InterfacesEventArgs ea = new InterfacesEventArgs (i);
                                try {
                                        OnInterfaces (ea);
                                } finally {
                                        if (ReceiveInterfaces != null)
                                                ReceiveInterfaces (this, ea);
                                }
                        }
                }

                protected virtual void OnInterfaces (InterfacesEventArgs e) {}

                private void Fields (FieldInfo[] f)
                {
                        if (ShowFields) {
                                FieldsEventArgs ea = new FieldsEventArgs (f);
                                try {
                                        OnFields (ea);
                                } finally {
                                        if (ReceiveFields != null)
                                                ReceiveFields (this, ea);
                                }
                        }
                }

                protected virtual void OnFields (FieldsEventArgs e) {}

                private void Properties (PropertyInfo[] p)
                {
                        if (ShowProperties) {
                                PropertiesEventArgs ea = new PropertiesEventArgs (p);
                                try {
                                        OnProperties (ea);
                                } finally {
                                        if (ReceiveProperties != null)
                                                ReceiveProperties (this, ea);
                                }
                        }
                }

                protected virtual void OnProperties (PropertiesEventArgs e) {}

                private void Events (EventInfo[] e)
                {
                        if (ShowEvents) {
                                EventsEventArgs ea = new EventsEventArgs (e);
                                try {
                                        OnEvents (ea);
                                } finally {
                                        if (ReceiveEvents != null)
                                                ReceiveEvents (this, ea);
                                }
                        }
                }

                protected virtual void OnEvents (EventsEventArgs e) {}

                private void Constructors (ConstructorInfo[] c)
                {
                        if (ShowConstructors) {
                                ConstructorsEventArgs ea = new ConstructorsEventArgs 
(c);
                                try {
                                        OnConstructors (ea);
                                } finally {
                                        if (ReceiveConstructors != null)
                                                ReceiveConstructors (this, ea);
                                }
                        }
                }

                protected virtual void OnConstructors (ConstructorsEventArgs e)
                {
                }

                private void Methods (MethodInfo[] m)
                {
                        if (ShowMethods) {
                                MethodsEventArgs ea = new MethodsEventArgs (m);
                                try {
                                        OnMethods (ea);
                                } finally {
                                        if (ReceiveMethods != null)
                                                ReceiveMethods (this, ea);
                                }
                        }
                }

                protected virtual void OnMethods (MethodsEventArgs e) {}

                public event TypeEventHandler         ReceiveTypes;
                public event BaseTypeEventHandler     ReceiveBaseType;
                public event InterfacesEventHandler   ReceiveInterfaces;
                public event FieldsEventHandler       ReceiveFields;
                public event PropertiesEventHandler   ReceiveProperties;
                public event EventsEventHandler       ReceiveEvents;
                public event ConstructorsEventHandler ReceiveConstructors;
                public event MethodsEventHandler      ReceiveMethods;
        }

        public class IndentingTextWriter : TextWriter {

                private TextWriter _writer;

                private int indentLevel = 0;
                private int indentSize = 4;
                private bool needIndent = true;
                private char indentChar = ' ';

                public IndentingTextWriter (TextWriter writer)
                {
                        _writer = writer;
                }

                public int IndentLevel {
                        get {return indentLevel;}
                        set {indentLevel = value;}
                }

                public int IndentSize {
                        get {return indentSize;}
                        set {indentSize = value;}
                }

                public char IndentChar {
                        get {return indentChar;}
                        set {indentChar = value;}
                }

                public void Indent ()
                {
                        ++IndentLevel;
                }

                public void Unindent ()
                {
                        --IndentLevel;
                }

                protected bool NeedIndent {
                        get {return needIndent;}
                        set {needIndent = value;}
                }

                protected virtual void WriteIndent ()
                {
                        NeedIndent = false;
                        Trace.WriteLine (String.Format(
                                "** WriteIndent: char='{0}',level={1},size={2}",
                                IndentChar, IndentLevel, IndentSize));
                        string indent = new string (IndentChar, 
                                        IndentLevel * IndentSize);
                        Write (indent);
                }

                protected override void Dispose (bool disposing)
                {
                        if (disposing)
                                _writer.Close ();
                }

                public override System.Text.Encoding Encoding {
                        get {return _writer.Encoding;}
                }

                public override void Write (string value)
                {
                        if (NeedIndent)
                                WriteIndent ();
                        _writer.Write (value);
                }

                public override void WriteLine ()
                {
                        if (NeedIndent)
                                WriteIndent ();
                        _writer.WriteLine ();
                        NeedIndent = true;
                }

                public override void WriteLine (string value)
                {
                        Trace.WriteLine (String.Format(
                                "** WriteLine: NeedIndent={0}", NeedIndent));
                        if (NeedIndent)
                                WriteIndent ();
                        _writer.WriteLine (value);
                        NeedIndent = true;
                }
        }

        public class Indenter : IDisposable {

                private IndentingTextWriter _writer;
                // private int level;

                public Indenter (IndentingTextWriter writer) 
                        : this (writer, 1)
                {
                }

                public Indenter (IndentingTextWriter writer, int level)
                {
                        _writer = writer;
                        // XXX: _writer.IndentLevel += level;
                        _writer.Indent ();
                }

                public void Dispose ()
                {
                        // XXX: _writer.IndentLevel -= level;
                        _writer.Unindent ();
                        Trace.WriteLine (String.Format(
                                "** Disposing; indentlevel={0}", 
                                _writer.IndentLevel));
                }
        }

        class VerboseTreeTypeDisplayer : TypeDisplayer {

                private IndentingTextWriter _writer;

                public VerboseTreeTypeDisplayer (TextWriter writer)
                {
                        _writer = new IndentingTextWriter (writer);
                        _writer.IndentChar = ' ';
                        _writer.IndentSize = 2;
                }

                public IndentingTextWriter Writer {
                        get {return _writer;}
                }

                private void PrintMemberInfo (MemberInfo mi)
                {
                        Writer.WriteLine ("DeclaringType={0}", mi.DeclaringType);
                        Writer.WriteLine ("MemberType={0}", mi.MemberType);
                        Writer.WriteLine ("Name={0}", mi.Name);
                        Writer.WriteLine ("ReflectedType={0}", mi.ReflectedType);
                        /*
                         * Not liked by Constructors: on type MethodsEventHandler
                        Writer.WriteLine ("GetCustomAttributes():");
                        using (Indenter n1 = new Indenter (Writer)) {
                                object[] attrs = mi.GetCustomAttributes (true);
                                foreach (object a in attrs)
                                        Writer.WriteLine (a);
                        }
                         */
                }

                protected override void OnType (TypeEventArgs e)
                {
                        string t = null;

                        if (e.Type.IsClass)
                                t = "class";
                        else if (e.Type.IsEnum)
                                t = "enum";
                        else if (e.Type.IsValueType)
                                t = "struct";
                        else if (e.Type.IsInterface)
                                t = "interface";
                        else
                                t = "type";

                        Writer.WriteLine (String.Format ("{0,-11}{1}", t, 
e.Type.ToString()));
                        using (Indenter n1 = new Indenter (Writer)) {
                                if (ShowTypeProperties) {
                                        Writer.WriteLine ("System.Type Properties:");
                                        using (Indenter n2 = new Indenter (Writer))
                                                PrintType (e.Type);
                                }
                        }
                }

                protected string PrintEnumValue (Type enumType, object value)
                {
                        return Enum.Format(enumType, value, "f") + " (" + value + ")";
                }

                protected void PrintType (Type i)
                {
                        PrintMemberInfo (i);
                        Writer.WriteLine ("Delimiter={0}", Type.Delimiter);
                        if (ShowMonoBroken)
                                Writer.WriteLine ("EmptyTypes={0}", 
Type.EmptyTypes.ToString());
                        Writer.WriteLine ("FilterAttribute={0}", Type.FilterAttribute);
                        Writer.WriteLine ("FilterName={0}", Type.FilterName);
                        Writer.WriteLine ("FilterNameIgnoreCase={0}", 
Type.FilterNameIgnoreCase);
                        if (ShowMonoBroken)
                                Writer.WriteLine ("Missing={0}", Type.Missing);

                        if (ShowMonoBroken)
                                Writer.WriteLine ("Assembly={0}", i.Assembly);
                        using (Indenter n1 = new Indenter (Writer)) {
                                if (ShowMonoBroken)
                                        Writer.WriteLine ("CodeBase={0}", 
i.Assembly.CodeBase);
                                Writer.WriteLine ("EntryPoint={0}", 
i.Assembly.EntryPoint);
#if MONO_BROKEN
                                if (ShowMonoBroken)
                                        Writer.WriteLine ("EscapedCodeBase={0}", 
i.Assembly.EscapedCodeBase);
#endif
                                Writer.WriteLine ("Evidence={0}", i.Assembly.Evidence);
                                if (ShowMonoBroken)
                                        Writer.WriteLine ("FullName={0}", 
i.Assembly.FullName);
#if MONO_BROKEN
                                if (ShowMonoBroken)
                                        Writer.WriteLine ("GlobalAssemblyCache={0}", 
i.Assembly.GlobalAssemblyCache);
#endif
                                Writer.WriteLine ("Location={0}", i.Assembly.Location);
                        }
                        if (ShowMonoBroken)
                                Writer.WriteLine ("AssemblyQualifiedName={0}", 
i.AssemblyQualifiedName);
                        Writer.WriteLine ("Attributes={0}", 
                                PrintEnumValue (typeof(TypeAttributes), i.Attributes));
                        Writer.WriteLine ("BaseType={0}", i.BaseType);
                        Writer.WriteLine ("DeclaringType={0}", i.DeclaringType);
                        Writer.WriteLine ("DefaultBinder={0}", Type.DefaultBinder);
                        Writer.WriteLine ("FullName={0}", i.FullName);
                        Writer.WriteLine ("GUID={0}", i.GUID);
                        Writer.WriteLine ("HasElementType={0}", i.HasElementType);
                        Writer.WriteLine ("IsAbstract={0}", i.IsAbstract);
                        Writer.WriteLine ("IsAnsiClass={0}", i.IsAnsiClass);
                        Writer.WriteLine ("IsArray={0}", i.IsArray);
                        Writer.WriteLine ("IsAutoClass={0}", i.IsAutoClass);
                        Writer.WriteLine ("IsAutoLayout={0}", i.IsAutoLayout);
                        Writer.WriteLine ("IsByRef={0}", i.IsByRef);
                        Writer.WriteLine ("IsClass={0}", i.IsClass);
                        Writer.WriteLine ("IsCOMObject={0}", i.IsCOMObject);
                        Writer.WriteLine ("IsContextful={0}", i.IsContextful);
                        Writer.WriteLine ("IsEnum={0}", i.IsEnum);
                        Writer.WriteLine ("IsExplicitLayout={0}", i.IsExplicitLayout);
                        Writer.WriteLine ("IsImport={0}", i.IsImport);
                        Writer.WriteLine ("IsInterface={0}", i.IsInterface);
                        Writer.WriteLine ("IsLayoutSequential={0}", 
i.IsLayoutSequential);
                        Writer.WriteLine ("IsMarshalByRef={0}", i.IsMarshalByRef);
                        Writer.WriteLine ("IsNestedAssembly={0}", i.IsNestedAssembly);
                        Writer.WriteLine ("IsNestedFamORAssem={0}", 
i.IsNestedFamORAssem);
                        Writer.WriteLine ("IsNestedPrivate={0}", i.IsNestedPrivate);
                        Writer.WriteLine ("IsNotPublic={0}", i.IsNotPublic);
                        Writer.WriteLine ("IsPointer={0}", i.IsPointer);
                        Writer.WriteLine ("IsPrimitive={0}", i.IsPrimitive);
                        Writer.WriteLine ("IsPublic={0}", i.IsPublic);
                        Writer.WriteLine ("IsSealed={0}", i.IsSealed);
                        Writer.WriteLine ("IsSerializable={0}", i.IsSerializable);
                        Writer.WriteLine ("IsSpecialName={0}", i.IsSpecialName);
                        Writer.WriteLine ("IsUnicodeClass={0}", i.IsUnicodeClass);
                        Writer.WriteLine ("IsValueType={0}", i.IsValueType);
                        Writer.WriteLine ("Module={0}", i.Module);
                        Writer.WriteLine ("Namespace={0}", i.Namespace);
                        Writer.WriteLine ("TypeHandle={0}", i.TypeHandle);
                        if (ShowMonoBroken)
                                Writer.WriteLine ("TypeInitializer={0}", 
i.TypeInitializer);
                        Writer.WriteLine ("UnderlyingSystemType={0}", 
i.UnderlyingSystemType);
                }

                protected override void OnInterfaces (InterfacesEventArgs e)
                { 
                        using (Indenter n = new Indenter (Writer)) {
                                Writer.WriteLine ("Interfaces:");
                                using (Indenter n2 = new Indenter (Writer)) {
                                        foreach (Type i in e.Interfaces) {
                                                Writer.WriteLine (i);
                                                if (VerboseOutput) {
                                                        using (Indenter n3 = new 
Indenter (Writer)) {
                                                                PrintType (i);
                                                        }
                                                }
                                        }
                                }
                        }
                }

                protected void PrintFieldInfo (FieldInfo f)
                {
                        if (VerboseOutput) {
                                PrintMemberInfo (f);
                                Writer.WriteLine ("Attributes={0}", 
                                        PrintEnumValue (typeof(FieldAttributes), 
f.Attributes));
                                Writer.WriteLine ("FieldHandle={0}", f.FieldHandle);
                                Writer.WriteLine ("FieldType={0}", f.FieldType);
                                Writer.WriteLine ("IsAssembly={0}", f.IsAssembly);
                                Writer.WriteLine ("IsFamily={0}", f.IsFamily);
                                Writer.WriteLine ("IsFamilyAndAssembly={0}", 
f.IsFamilyAndAssembly);
                                Writer.WriteLine ("IsFamilyOrAssembly={0}", 
f.IsFamilyOrAssembly);
                                Writer.WriteLine ("IsInitOnly={0}", f.IsInitOnly);
                                Writer.WriteLine ("IsLiteral={0}", f.IsLiteral);
                                Writer.WriteLine ("IsNotSerialized={0}", 
f.IsNotSerialized);
                                Writer.WriteLine ("IsPinvokeImpl={0}", 
f.IsPinvokeImpl);
                                Writer.WriteLine ("IsPrivate={0}", f.IsPrivate);
                                Writer.WriteLine ("IsPublic={0}", f.IsPublic);
                                Writer.WriteLine ("IsSpecialName={0}", 
f.IsSpecialName);
                                Writer.WriteLine ("IsStatic={0}", f.IsStatic);
                                if (f.IsStatic && f.IsLiteral) {
                                        Writer.Write ("Enumeration Value: ");
                                        string s = Enum.Format (f.DeclaringType, 
f.GetValue(null), "x");
                                        Writer.WriteLine ("0x{0}", s);
                                }
                                /*
                                if (f.DeclaringType.IsEnum && f.IsStatic) {
                                        Writer.Write ("Enumeration Value (2): ");
                                        string s = Enum.Format (f.DeclaringType, 
f.GetValue(null), "x");
                                        Writer.WriteLine ("0x{0}", s);
                                }
                                 */
                        }
                }

                protected override void OnFields (FieldsEventArgs e)
                {
                        using (Indenter n1 = new Indenter (Writer)) {
                                Writer.WriteLine ("Fields:");
                                using (Indenter n2 = new Indenter (Writer)) {
                                        foreach (FieldInfo f in e.Fields) {
                                                Writer.WriteLine (f);
                                                using (Indenter n3 = new Indenter 
(Writer)) {
                                                        PrintFieldInfo (f);
                                                }
                                        }
                                }
                        }
                }

                protected void PrintPropertyInfo (PropertyInfo p)
                {
                        if (VerboseOutput) {
                                PrintMemberInfo (p);
                                Writer.WriteLine ("Attributes={0}", 
                                        PrintEnumValue (typeof(PropertyAttributes), 
p.Attributes));
                                Writer.WriteLine ("CanRead={0}", p.CanRead);
                                Writer.WriteLine ("CanWrite={0}", p.CanWrite);
                                Writer.WriteLine ("IsSpecialName={0}", 
p.IsSpecialName);
                                Writer.WriteLine ("PropertyType={0}", p.PropertyType);
                        }
                }

                protected override void OnProperties (PropertiesEventArgs e)
                {
                        using (Indenter n1 = new Indenter (Writer)) {
                                Writer.WriteLine ("Properties:");
                                using (Indenter n2 = new Indenter (Writer)) {
                                        foreach (PropertyInfo p in e.Properties) {
                                                Writer.WriteLine (p);
                                                using (Indenter n3 = new Indenter 
(Writer)) {
                                                        PrintPropertyInfo (p);
                                                }
                                        }
                                }
                        }
                }

                protected void PrintEventInfo (EventInfo i)
                {
                        if (VerboseOutput) {
                                PrintMemberInfo (i);
                                Writer.WriteLine ("Attributes={0}", PrintEnumValue 
(typeof(EventAttributes), i.Attributes));
                                Writer.WriteLine ("EventHandlerType={0}", 
i.EventHandlerType);
                                Writer.WriteLine ("IsMulticast={0}", i.IsMulticast);
                                Writer.WriteLine ("IsSpecialName={0}", 
i.IsSpecialName);
                        }
                }

                protected override void OnEvents (EventsEventArgs e)
                {
                        using (Indenter n1 = new Indenter (Writer)) {
                                Writer.WriteLine ("Events:");
                                using (Indenter n2 = new Indenter (Writer)) {
                                        foreach (EventInfo i in e.Events) {
                                                Writer.WriteLine (i);
                                                using (Indenter n3 = new Indenter 
(Writer)) {
                                                        PrintEventInfo (i);
                                                }
                                        }
                                }
                        }
                }

                private void PrintMethodBase (MethodBase mb)
                {
                        PrintMemberInfo (mb);
                        Writer.WriteLine ("Attributes={0}", 
                                PrintEnumValue (typeof(MethodAttributes), 
mb.Attributes));
                        Writer.WriteLine ("CallingConvention={0}", 
mb.CallingConvention);
                        Writer.WriteLine ("IsAbstract={0}", mb.IsAbstract);
                        Writer.WriteLine ("IsAssembly={0}", mb.IsAssembly);
                        Writer.WriteLine ("IsConstructor={0}", mb.IsConstructor);
                        Writer.WriteLine ("IsFamily={0}", mb.IsFamily);
                        Writer.WriteLine ("IsFamilyAndAssembly={0}", 
mb.IsFamilyAndAssembly);
                        Writer.WriteLine ("IsFamilyOrAssembly={0}", 
mb.IsFamilyOrAssembly);
                        Writer.WriteLine ("IsFinal={0}", mb.IsFinal);
                        Writer.WriteLine ("IsHideBySig={0}", mb.IsHideBySig);
                        Writer.WriteLine ("IsPrivate={0}", mb.IsPrivate);
                        Writer.WriteLine ("IsPublic={0}", mb.IsPublic);
                        Writer.WriteLine ("IsSpecialName={0}", mb.IsSpecialName);
                        Writer.WriteLine ("IsStatic={0}", mb.IsStatic);
                        Writer.WriteLine ("IsVirtual={0}", mb.IsVirtual);
                        Writer.WriteLine ("MethodHandle={0}", mb.MethodHandle);
                }

                protected void PrintConstructorInfo (ConstructorInfo c)
                {
                        if (VerboseOutput) {
                                PrintMethodBase (c);
                        }
                }

                protected override void OnConstructors (ConstructorsEventArgs e)
                {
                        using (Indenter n1 = new Indenter (Writer)) {
                                Writer.WriteLine ("Constructors:");
                                using (Indenter n2 = new Indenter (Writer)) {
                                        foreach (ConstructorInfo c in e.Constructors) {
                                                Writer.WriteLine (c);
                                                using (Indenter n3 = new Indenter 
(Writer)) {
                                                        PrintConstructorInfo (c);
                                                }
                                        }
                                }
                        }
                }

                protected void PrintMethodInfo (MethodInfo m)
                {
                        if (VerboseOutput) {
                                PrintMethodBase (m);
                                Writer.WriteLine ("ReturnType={0}", m.ReturnType);
                                Writer.WriteLine ("ReturnTypeCustomAttributes={0}", 
                                        /* PrintEnumValue 
(typeof(m.ReturnTypeCustomAttributes), m.ReturnTypeCustomAttributes) */
                                        m.ReturnTypeCustomAttributes);
                        }
                }

                protected override void OnMethods (MethodsEventArgs e)
                {
                        using (Indenter n1 = new Indenter (Writer)) {
                                Writer.WriteLine ("Methods:");
                                using (Indenter n2 = new Indenter (Writer)) {
                                        foreach (MethodInfo m in e.Methods) {
                                                Writer.WriteLine (m);
                                                using (Indenter n3 = new Indenter 
(Writer)) {
                                                        PrintMethodInfo (m);
                                                }
                                        }
                                }
                        }
                }
        }

        public class TypeLoader {

                // String collection
                private ICollection assemblies = null;

                private bool matchFullName = true;
                private bool matchName = false;
                private bool matchBase = false;
                private bool matchMethodReturnType = false;
                private bool matchNamespace = false;

                public bool MatchFullName {
                        get {return matchFullName;}
                        set {matchFullName = value;}
                }

                public bool MatchClassName {
                        get {return matchName;}
                        set {matchName = value;}
                }

                public bool MatchBase {
                        get {return matchBase;}
                        set {matchBase = value;}
                }

                public bool MatchMethodReturnType {
                        get {return matchMethodReturnType;}
                        set {matchMethodReturnType = value;}
                }

                public bool MatchNamespace {
                        get {return matchNamespace;}
                        set {matchNamespace = value;}
                }

                public TypeLoader ()
                {
                }

                public TypeLoader (ICollection assemblies)
                {
                        this.assemblies = assemblies;
                }

                public ICollection Assemblies {
                        get {return assemblies;}
                        set {assemblies = value;}
                }

                public ICollection LoadTypes (string match)
                {
                        if (assemblies == null)
                                throw new ArgumentNullException ("Assemblies");

                        IList found = new ArrayList ();

                        foreach (string a in assemblies) {
                                LoadMatchingTypesFrom (a, match, found);
                        }

                        return found;
                }

                private void LoadMatchingTypesFrom (string where, string match, IList 
types)
                {
                        Regex re = new Regex (match);
                        try {
                                Assembly a = Assembly.LoadFrom (where);
                                Type[] _types = a.GetTypes();
                                foreach (Type t in _types) {
                                        if (Matches (re, t))
                                                types.Add (t);
                                }
                        } catch (Exception e) {
                                Trace.WriteLine (String.Format (
                                        "Unable to load type regex `{0}' from `{1}'.",
                                        match, where));
                                Trace.WriteLine (e.ToString());
                        }
                }

                private bool Matches (Regex r, Type t)
                {
                        bool f, c, b, rt, n;
                        f = c = b = rt = n = false;
                        if (MatchFullName)
                                f = r.Match(t.FullName).Success;
                        if (MatchClassName)
                                c = r.Match(t.Name).Success;
                        if (MatchNamespace)
                                n = r.Match(t.Namespace).Success;
                        if (MatchBase) {
                                b = (!MatchFullName ? false : r.Match 
(t.BaseType.FullName).Success) ||
                                    (!MatchClassName ? false : r.Match 
(t.BaseType.Name).Success) ||
                                    (!MatchNamespace ? false : r.Match 
(t.BaseType.Namespace).Success);
                        }
                        // TODO: MatchMethodReturnType
                        Trace.WriteLine (String.Format("TypeLoader.Matches: c={0}, 
b={1}, rt={2}, n={3}", c, b, rt, n));
                        return f || c || b || rt || n;
                }
        }

        internal class TextGrouper {
                private int leftMargin = 0;
                private int rightMargin = 80;
                private int subsequentIndent = 0;

                public int LeftMargin {
                        get {return leftMargin;}
                        set {leftMargin = value;}
                }

                public int RightMargin {
                        get {return rightMargin;}
                        set {rightMargin = value;}
                }

                public int SubsequentIndent {
                        get {return subsequentIndent;}
                        set {subsequentIndent = value;}
                }

                public TextGrouper ()
                        : this (0)
                {
                }

                public TextGrouper (int leftMargin)
                        : this (leftMargin, 80)
                {
                }

                public TextGrouper (int leftMargin, int rightMargin)
                        : this (leftMargin, rightMargin, 0)
                {
                }

                public TextGrouper (int leftMargin, int rightMargin, int 
subsequentIndent)
                {
                        this.leftMargin = leftMargin;
                        this.rightMargin = rightMargin;
                        this.subsequentIndent = subsequentIndent;
                }

                private void WrapText (string text, int width, IList lines)
                {
                        if (text.Length <= width) {
                                lines.Add (text);
                                return;
                        }

                        while (text.Length > width) {
                                int b = width;
                                if (!Char.IsWhiteSpace(text[b])) {
                                        b = text.LastIndexOf (' ', b);
                                        if (b == -1)
                                                // couldn't find an earlier word break
                                                b = width;
                                }
                                lines.Add (text.Substring (0, b));
                                text = text.Substring (b).Trim();
                        }
                        lines.Add (text);
                }

                private ICollection WrapText (string text, int width)
                {
                        ArrayList lines = new ArrayList ();
                        string[] paragraphs = text.Split(new char[] {'\n'});
                        foreach (string p in paragraphs)
                                WrapText (p, width, lines);
                        return lines;
                }

                public string Group (string text)
                {
                        // should be "- followingIndent", but need an extra space for 
the '\n'.
                        int width = (RightMargin - LeftMargin) - (SubsequentIndent+1);
                        StringBuilder sb = new StringBuilder ();
                        string format1 = "{1}";
                        string formatN = "{0,-" + (LeftMargin + SubsequentIndent) + 
"}{1}";
                        ICollection c = WrapText (text, width);
                        int last = c.Count;
                        string format = format1;
                        foreach (string s in c) {
                                string line = String.Format (format, "", s);
                                sb.Append (line);
                                if (--last != 0) {
                                        format = formatN;
                                        sb.Append ("\n");
                                }
                        }
                        return sb.ToString();
                }
        }

        internal class OptionException : Exception {

                public char ShortForm;

                public OptionException (string reason, char shortForm )
                        : base (reason)
                {
                        this.ShortForm = shortForm;
                }

                public OptionException (string reason)
                        : base (reason)
                {
                }

                public OptionException (string reason, Exception inner)
                        : base (reason, inner)
                {
                }
        }

        internal class ProgramOptions {

                private class Option {
                        public char   ShortForm = '\0';
                        public string LongForm = null;
                        public string Description = null;
                        public bool   Found = false;
                        public bool   HasArgument = false;
                        public string ArgumentValue = null;
                        public string ArgumentDescription = null;

                        public Option (char shortForm, string longForm, string 
description, string argDesc, bool hasArgument)
                        {
                                ShortForm = shortForm;
                                LongForm = longForm;
                                Description = description;
                                HasArgument = hasArgument;
                                ArgumentDescription = argDesc;
                        }

                        public Option (char shortForm, string description)
                        {
                                ShortForm = shortForm;
                                Description = description;
                        }

                        public Option (string longForm, string description)
                        {
                                LongForm = longForm;
                                Description = description;
                        }
                }

                // Option array
                private ArrayList options = new ArrayList ();

                // string array
                private ArrayList unmatched = new ArrayList ();

                public IList UnmatchedOptions {
                        get {return unmatched;}
                }

                public ProgramOptions ()
                {
                }

                private void AddOption (Option opt)
                {
                        options.Add (opt);
                }

                public void AddHelpOption ()
                {
                        AddOption (new Option ('h', "help", "Display this help and 
exit.", null, false));
                }

                public void AddOption (char shortForm, string description)
                {
                        AddOption (new Option (shortForm, description));
                }

                public void AddArgumentOption (char shortForm, string description, 
string argument)
                {
                        AddOption (new Option (shortForm, null, description, argument, 
true));
                }

                public void AddOption (string longForm, string description)
                {
                        AddOption (new Option (longForm, description));
                }

                public void AddArgumentOption (string longForm, string description, 
string argument)
                {
                        AddOption (new Option ('\0', longForm, description, argument, 
true));
                }

                public void AddOption (char shortForm, string longForm, string 
description)
                {
                        AddOption (new Option (shortForm, longForm, description, null, 
false));
                }

                public void AddArgumentOption (char shortForm, string longForm, string 
description, string argument)
                {
                        AddOption (new Option (shortForm, longForm, description, 
argument, true));
                }

                public virtual void ParseOptions (string[] options)
                {
                        int len = options.Length;
                        bool handle = true;
                        for (int cur = 0; cur != len; ++cur) {
                                string option = options[cur];
                                // necessary?
                                if (option == null || option.Length == 0)
                                        continue;
                                if (handle) {
                                        if (option.StartsWith ("-")) {
                                                // possible option
                                                if (option == "--")
                                                        handle = false;
                                                else if (option.StartsWith ("--"))
                                                        ParseLongOption (options, ref 
cur);
                                                else
                                                        ParseShortOptions (options, 
ref cur);
                                        }
                                        else
                                                unmatched.Add (option);
                                }
                                else
                                        unmatched.Add (option);
                        }
                }

                private void ParseLongOption (string[] args, ref int currentIndex)
                {
                        // get rid of "--"
                        string arg = args[currentIndex].Substring (2);
                        bool found = false;
                        foreach (Option o in options) {
                                if (o.LongForm == null)
                                        continue;
                                if (!arg.StartsWith(o.LongForm))
                                        continue;
                                found = true;
                                o.Found = true;
                                if (o.HasArgument) {
                                        try {
                                                o.ArgumentValue = arg.Substring 
(arg.IndexOf('=')+1);
                                        } catch (Exception e) {
                                                throw new OptionException (
                                                        "missing argument to option 
--" + o.LongForm,
                                                        e);
                                        }
                                }
                        }

                        if (!found)
                                throw new OptionException (
                                        String.Format ("Unrecognized option `{0}'", 
args[currentIndex]));
                }

                private void ParseShortOptions (string[] args, ref int currentIndex)
                {
                        string arg = args[currentIndex].Substring (1);
                        int needsArg = 0;
                        Option forArg = null;
                        for (int i = 0; i != arg.Length; ++i) {
                                bool found = false;
                                foreach (Option o in options) {
                                        if (o.ShortForm != arg[i])
                                                continue;
                                        found = true;
                                        o.Found = true;
                                        if (o.HasArgument) {
                                                ++needsArg;
                                                forArg = o;
                                        }
                                }
                                if (!found)
                                        throw new OptionException (
                                                String.Format("Unrecognized option 
`-{0}'", arg[i]));
                        }

                        if (needsArg > 1)
                                throw new OptionException ("too many options requiring 
arguments specified");
                        else if (needsArg == 1) {
                                if (currentIndex == (args.Length - 1))
                                        throw new OptionException ("missing argument 
to option -" + forArg.ShortForm);
                                ++currentIndex;
                                forArg.ArgumentValue = args[currentIndex];
                        }
                }

                public virtual void Clear ()
                {
                        foreach (Option o in options) {
                                o.Found = false;
                                o.ArgumentValue = null;
                        }
                }

                private static readonly string[] OptionFormats = 
                        {
                        // 0: no short, no long, no arg
                        "<invalid option format: 0>",
                        // 1: short only
                        "  -{0}",
                        // 2: long only
                        "      --{1}",
                        // 3: long & short
                        "  -{0}, --{1}",
                        // 4: no short, no long, arg
                        "<invalid option format: 4>",
                        // 5: short w/ arg
                        "  -{0} {2}",
                        // 6: long w/ arg
                        "      --{1}={2}",
                        // 7: short & long w/ arg
                        "  -{0}, --{1}={2}"
                        };

                public virtual string OptionsHelp {
                        get {
                                StringBuilder sb = new StringBuilder ();
                                foreach (Option o in options) {
                                        uint f_s =  Convert.ToUInt32 (o.ShortForm != 
'\0');
                                        uint f_l =  Convert.ToUInt32 (o.LongForm != 
null);
                                        uint f_h =  Convert.ToUInt32 (o.HasArgument);
                                        uint format = (f_s << 0) | (f_l << 1) | (f_h 
<< 2);
                                        string opt = String.Format 
(OptionFormats[format], 
                                                        o.ShortForm, 
                                                        o.LongForm, 
                                                        o.ArgumentDescription);
                                        string fmt = null;
                                        if (opt.Length < 30)
                                                fmt = "{0,-30}{1}";
                                        else
                                                fmt = "{0,-30}\n{2,-30}{1}";
                                        string d = new TextGrouper (30, 80, 2).Group 
(o.Description);
                                        sb.Append (String.Format (fmt, opt, d, ""));
                                        sb.Append ("\n");
                                }
                                return sb.ToString ();
                        }
                }

                public static readonly string ProgramName = 
Environment.GetCommandLineArgs()[0];

                public bool FoundOption (char shortForm)
                {
                        foreach (Option o in options) {
                                if (o.ShortForm != shortForm)
                                        continue;
                                return o.Found;
                        }
                        return false;
                }

                public bool FoundOption (string longForm)
                {
                        foreach (Option o in options) {
                                if (o.LongForm != longForm)
                                        continue;
                                return o.Found;
                        }
                        return false;
                }

                public string FoundOptionValue (char shortForm)
                {
                        foreach (Option o in options) {
                                if (o.ShortForm != shortForm)
                                        continue;
                                return o.ArgumentValue;
                        }
                        return null;
                }

                public string FoundOptionValue (string longForm)
                {
                        foreach (Option o in options) {
                                if (o.LongForm != longForm)
                                        continue;
                                return o.ArgumentValue;
                        }
                        return null;
                }

                public bool FoundHelp {
                        get {return FoundOption ('h');}
                }
        }

        internal class TypeIntrospectorOptions : ProgramOptions {

                private static char onlyAssemblies      = 'A';
                private static char addAssemblies       = 'a';
                private static char matchAll            = 'M';
                private static char matchFullName       = 'f';
                private static char matchClass          = 'C';
                private static char matchBase           = 'B';
                private static char matchNamespace      = 'N';
                private static char matchReturnType     = 'R';
                private static char showBase            = 'b';
                private static char showConstructors    = 'c';
                private static char showEvents          = 'e';
                private static char showFields          = 'f';
                private static char showInterfaces      = 'i';
                private static char showMethods         = 'm';
                private static char showProperties      = 'p';
                private static char showTypeProperties  = 't';
                private static char showNonPublic       = 'U';
                private static char showMonoBroken      = 'K';
                private static char showAll             = 'S';
                private static char showInheritedMembers= 'r';
                private static char verboseOutput       = 'v';
                private static char flattenHierarchy    = 'F';

                public TypeIntrospectorOptions ()
                {
                        AddArgumentOption (onlyAssemblies,  "only-assemblies",
                                "Only search for types within the specified " +
                                "assemblies.  Assemblies are searched for " +
                                "within the directories specified with " +
                                "--only-directories.", 
                                "<assembly-list>");
                        AddArgumentOption (addAssemblies,   "add-assemblies",
                                "Add the specified assemblies to the list of " +
                                "assemblies searched for types.", 
                                "<assembly-list>");
                        AddOption (matchAll,                "match-all",
                                "Type names should be matched in all locations"
                                );
                        AddOption (matchFullName,           "match-full-name",
                                "Match type names against the full type name " +
                                "(Namespace + Class Name).\n" +
                                "This is the default.");
                        AddOption (matchClass,              "match-class",
                                "Match type names against only the class name");
                        AddOption (matchBase,               "match-base",
                                "Match type names against the base class " + 
                                "name.\nMatching of the base name is " +
                                "identical to top-level type matches--it " +
                                "matches the namespace, class name, or full " +
                                "type name.");
                        AddOption (matchNamespace,          "match-namespace",
                                "Match the type's namespace.");
                        /*
                        AddOption (matchReturnType,         "match-return-type",
                                "Match the return type of methods");
                         */
                        AddOption (showBase,                "show-base",
                                "Show the base class.");
                        AddOption (showConstructors,        "show-constructors",
                                "Show the type's constructors.");
                        AddOption (showEvents,              "show-events",
                                "Show the type's events.");
                        AddOption (showFields,              "show-fields",
                                "Show the type's fields.");
                        AddOption (showInterfaces,          "show-interfaces",
                                "Show the type's interfaces");
                        AddOption (showMethods,             "show-methods",
                                "Show the type's methods.");
                        AddOption (showProperties,          "show-properties",
                                "Show the type's properties.");
                        AddOption (showTypeProperties,      "show-type-properties",
                                "Show the properties of the type's System.Type"+
                                "object.\nThis is not set by -S.");
                        AddOption (showInheritedMembers,    "show-inherited-members",
                                "Show inherited members (members declared by " +
                                "base classes).\nThis is not set by -S.");
                        AddOption (showNonPublic,           "show-non-public",
                                "Show non-public members.\n" + 
                                "This is not set by -S.");
                        AddOption (showMonoBroken,          "show-mono-broken",
                                "Some attributes shown in verbose output " +
                                "cause exceptions when run under Mono.  " +
                                "These attributes are not shown by default.  "+
                                "This option shows these disabled attributes."+
                                "\nThis is not set by -S.");
                        AddOption (showAll,                 "show-all",
                                "Show everything except System.Type "+
                                "properties, inherited members, non-public "+
                                "members, and \"broken\" Mono attributes.");
                        AddOption (verboseOutput,           "verbose-output",
                                "Print the contents of all the public " + 
                                "attributes of the reflection information " +
                                "classes.");
                        AddOption (flattenHierarchy,        "flatten-hierarchy",
                                "Static members of base types should be " + 
                                "displayed.");
                        AddHelpOption ();
                }

                public override void ParseOptions (string[] options)
                {
                        base.ParseOptions (options);

                        _showAll = base.FoundOption (showAll);
                        _matchAll = base.FoundOption (matchAll);
                }

                public IList Types {
                        get {return base.UnmatchedOptions;}
                }

                private bool _matchAll;

                public bool MatchAll {
                        get {return _matchAll;}
                }

                // default: true;
                public bool MatchFullName {
                        get {
                                if (!MatchClassName && !MatchNamespace && !MatchBase 
&& 
                                    !MatchReturnType)
                                        return true;
                                return MatchAll || base.FoundOption (matchFullName);
                        }
                }

                public bool MatchClassName {
                        get {
                                return MatchAll || base.FoundOption (matchClass);
                        }
                }

                public bool MatchNamespace {
                        get {
                                return MatchAll || base.FoundOption (matchNamespace);
                        }
                }

                public bool MatchBase {
                        get {
                                return MatchAll || base.FoundOption (matchBase);
                        }
                }

                public bool MatchReturnType {
                        get {
                                return MatchAll || base.FoundOption (matchReturnType);
                        }
                }

                private bool _showAll;

                public bool ShowAll {
                        get {
                                return _showAll;
                        }
                }

                public bool ShowBase {
                        get {
                                return ShowAll || base.FoundOption (showBase);
                        }
                }

                public bool ShowConstructors {
                        get {
                                return ShowAll || base.FoundOption (showConstructors);
                        }
                }

                public bool ShowEvents {
                        get {
                                return ShowAll || base.FoundOption (showEvents);
                        }
                }

                public bool ShowFields {
                        get {
                                return ShowAll || base.FoundOption (showFields);
                        }
                }

                public bool ShowInterfaces {
                        get {
                                return ShowAll || base.FoundOption (showInterfaces);
                        }
                }

                public bool ShowMethods {
                        get {
                                return ShowAll || base.FoundOption (showMethods);
                        }
                }

                public bool ShowProperties {
                        get {
                                return ShowAll || base.FoundOption (showProperties);
                        }
                }

                public bool ShowTypeProperties {
                        get {
                                return base.FoundOption (showTypeProperties);
                        }
                }

                public bool ShowInheritedMembers {
                        get {
                                return base.FoundOption (showInheritedMembers);
                        }
                }

                public bool ShowNonPublic {
                        get {
                                return base.FoundOption (showNonPublic);
                        }
                }

                public bool ShowMonoBroken {
                        get {
                                return base.FoundOption (showMonoBroken);
                        }
                }

                public bool FlattenHierarchy {
                        get {
                                return base.FoundOption (flattenHierarchy);
                        }
                }

                public bool VerboseOutput {
                        get {
                                return base.FoundOption (verboseOutput);
                        }
                }

                private static string[] GetDefaultAssemblies ()
                {
                        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies 
();

                        string sysdir = null;

                        foreach (Assembly a in assemblies) {
                                string codebase = a.CodeBase;
                                if (codebase.EndsWith ("corlib.dll")) {
                                        sysdir = codebase.Substring (0, 
codebase.LastIndexOf ("/"));
                                        break;
                                }
                        }

                        return Directory.GetFiles (new Uri (sysdir).LocalPath, 
"*.dll");
                }

                public ICollection Assemblies {
                        get {
                                string o = base.FoundOptionValue (onlyAssemblies);
                                string a = base.FoundOptionValue (addAssemblies);
                                ArrayList r = new ArrayList ();

                                if (o == null) {
                                        r.AddRange (GetDefaultAssemblies ());
                                }
                                else {
                                        r.AddRange (o.Split (Path.PathSeparator));
                                }

                                if (a != null)
                                        r.AddRange (a.Split (Path.PathSeparator));

                                return r;
                        }
                }

                public override string OptionsHelp {
                        get {
                                StringBuilder sb = new StringBuilder ();
                                TextGrouper tg0 = new TextGrouper ();
                                TextGrouper tg4 = new TextGrouper (4, 80, 0);
                                sb.Append (
                                        "Prints out type information\n" +
                                        "\n" +
                                        "Usage: " + ProgramName + " [options] 
<types>\n" +
                                        "\n" +
                                        "Where [options] can include:\n");
                                sb.Append (base.OptionsHelp);
                                sb.Append (
                                        "\n" + 
                                        tg0.Group (
                                                "<assembly-list> is a `" + 
Path.PathSeparator + "'-delimited list.  " + 
                                                "For example, `" + 
                                                String.Format ("foo{0}bar{0}baz", 
                                                        Path.PathSeparator) + "' is a 
valid list.\n") +
                                        "\n" +
                                        tg0.Group (
                                                "<types> is interpreted as a regular 
expression.  As regular expression " + 
                                                "meta-characters are seldom used in 
class names, specifying a type name " +
                                                "looks for all types that have the 
specified type name as a substring.") +
                                        "\n\n"
                                        );
                                sb.Append ("The default assemblies are:\n");
                                foreach (string s in GetDefaultAssemblies ()) {
                                        sb.Append (String.Format ("  {0}\n", s));
                                }
                                sb.Append ("\n");
                                sb.Append (String.Format (
                                        "Examples:\n" +
                                        "  {0} Type\n", ProgramName));
                                sb.Append (String.Format ("    {0}", tg4.Group ("Finds 
all types that have `Type' (case-sensitive) as part of their name.")));
                                sb.Append (String.Format (
                                                "\n\n" +
                                                "  {0} [Tt][Yy][Pp][Ee]\n", 
ProgramName));
                                sb.Append (String.Format ("    {0}", tg4.Group ("Finds 
all types that have `Type' (case-insensitive) as part of their name.")));
                                sb.Append (String.Format (
                                                "\n\n" +
                                                "  {0} -A my-assembly.dll MyType\n", 
ProgramName));
                                sb.Append (String.Format ("    {0}", tg4.Group ("Finds 
all types that have `MyType' as part of their name within the assembly 
`my-assembly'.")));
                                sb.Append (String.Format (
                                                "\n\n" +
                                                "  {0} -SKt MyType\n", ProgramName));
                                sb.Append (String.Format ("    {0}", tg4.Group ("Find 
all types that have `MyType' as part of their name, and for those types show all 
information (-S) including information Mono generates exceptions for (-K) and show the 
values of the public attributes of the System.Type object for the type.")));
                                return sb.ToString ();
                        }
                }
        }

        public class ConsoleOutput {

                private static void TraceStringArray (string message, IEnumerable 
contents)
                {
                        Trace.WriteLine (message);
                        foreach (string s in contents) {
                                Trace.WriteLine ("  " + s);
                        }
                }

                public static void Main (string[] args)
                {
                        TypeIntrospectorOptions options = new TypeIntrospectorOptions 
();

                        try {
                                options.ParseOptions (args);
                        } catch (Exception e) {
                                Console.WriteLine (e.Message);
                                Console.WriteLine ("See `{0} --help' for more 
information", ProgramOptions.ProgramName);
                                // Console.WriteLine ("** Full Message continues:\n" + 
e);
                                return;
                        }

                        if (options.FoundHelp) {
                                Console.WriteLine (options.OptionsHelp);
                                return;
                        }

                        if (options.Types.Count == 0) {
                                Console.WriteLine ("No types specified.");
                                Console.WriteLine ("See `{0} --help' for more 
information", ProgramOptions.ProgramName);
                                return;
                        }

                        TraceStringArray ("Search Assemblies: ", options.Assemblies);
                        TraceStringArray ("Search for Types: ", options.Types);

                        TypeLoader loader = new TypeLoader (options.Assemblies);
                        loader.MatchBase = options.MatchBase;
                        loader.MatchFullName = options.MatchFullName;
                        loader.MatchClassName = options.MatchClassName;
                        loader.MatchNamespace = options.MatchNamespace;
                        loader.MatchMethodReturnType = options.MatchReturnType;

                        TypeDisplayer p = new VerboseTreeTypeDisplayer (Console.Out);
                        p.VerboseOutput = options.VerboseOutput;
                        p.ShowBase = options.ShowBase;
                        p.ShowConstructors = options.ShowConstructors;
                        p.ShowEvents = options.ShowEvents;
                        p.ShowFields = options.ShowFields;
                        p.ShowInterfaces = options.ShowInterfaces;
                        p.ShowMethods = options.ShowMethods;
                        p.ShowProperties = options.ShowProperties;
                        p.ShowTypeProperties = options.ShowTypeProperties;
                        p.ShowInheritedMembers = options.ShowInheritedMembers;
                        p.ShowNonPublic = options.ShowNonPublic;
                        p.ShowMonoBroken = options.ShowMonoBroken;
                        p.FlattenHierarchy = options.FlattenHierarchy;

                        foreach (string t in options.Types) {
                                try {
                                        ICollection typesFound = loader.LoadTypes (t);
                                        if (typesFound.Count > 0)
                                                foreach (Type type in 
loader.LoadTypes(t))
                                                        p.Parse (type);
                                        else
                                                Console.WriteLine ("Unable to find 
type `{0}'.", t);
                                } catch (Exception e) {
                                        Console.WriteLine ("Unable to parse type 
`{0}': {1}.", t, e.ToString());
                                }
                        }
                }
        }
}

Reply via email to