context: //
  // file:	peer.cs
  // author:	Dan Lewis (dihlewis@yahoo.co.uk)
  // 		(C) 2002
  //
  
  using System;
  using System.Reflection;
  using System.Collections;
  
  class Peer {
  	public Peer (Type clr_type, string name, bool is_opaque) {
  		this.clr_type = clr_type;
  		this.name = name;
  		this.is_opaque = is_opaque;
  
  		this.nearest_base = null;	// resolve later
  		this.underlying = null;
  		this.enum_constants = null;
  		this.fields = new PeerFieldCollection ();
  
  		this.is_enum = CLRIsEnum (clr_type);
  		this.is_value_type = CLRIsValueType (clr_type);
  	}
  
  	public string Name {
  		get { return name; }
  	}
  
  	public Type CLRType {
  		get { return clr_type; }
  	}
  
  	public bool IsOpaque {
  		get { return is_opaque; }
  	}
  
  	public bool IsValueType {
  		get { return is_value_type; }
  	}
  
  	public bool IsEnum {
  		get { return is_enum; }
  	}
  
  	public Peer NearestBase {
  		get { return nearest_base; }
  		set { nearest_base = value; }
  	}
  
  	public Peer UnderlyingPeer {
  		get { return underlying; }
  		set { underlying = value; }
  	}
  
  	public IDictionary EnumConstants {
  		get { return enum_constants; }
  		set { enum_constants = value; }
  	}
  
  	public PeerFieldCollection Fields {
  		get { return fields; }
  	}
  
  	public string GetTypedef (int refs) {
  		if (refs == 0)
  			return String.Format ("{0} ", name);
  
  		return String.Format ("{0} {1}", name, new string ('*', refs));
  	}
  
  	// internal
  
  	internal static bool CLRIsValueType (Type clr_type) {
  		return clr_type.IsValueType;
  		/*
  		if (clr_type.BaseType == null)
  			return false;
  	
  		return
  			clr_type.BaseType.FullName == "System.ValueType" ||
  			clr_type.BaseType.FullName == "System.Enum";
  		*/
  	}
  
  	internal static bool CLRIsEnum (Type clr_type) {
  		return clr_type.IsEnum;
  		/*
  		if (clr_type.BaseType == null)
  			return false;
  
  		return clr_type.BaseType.FullName == "System.Enum";
  		*/
  	}
  
  	internal static Type CLRUnderlyingType (Type clr_type) {
  		return Enum.GetUnderlyingType (clr_type);
  		/*
  		Type ebase = type.BaseType;
  
  		return (Type)ebase.InvokeMember ("GetUnderlyingType",
  			BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static,
  			null, null,
  			new object[] { type }
  		);
  		*/
  	}
  
  	// private
  
  	private Type clr_type;
  	private bool is_opaque;
  	private bool is_value_type;
  	private bool is_enum;
  
  	private string name;
  	private Peer nearest_base;
  	private Peer underlying;
  	private IDictionary enum_constants;
  	private PeerFieldCollection fields;
  }
  
  class PeerField {
  	public PeerField (Peer peer, string name) {
  		this.peer = peer;
  		this.name = name;
  	}
  
  	public Peer Peer {
  		get { return peer; }
  	}
  
  	public string Name {
  		get { return name; }
  	}
  
  	private Peer peer;
  	private string name;
  }
  
  class PeerFieldCollection : CollectionBase {
  	public void Add (PeerField f) {
  		List.Add (f);
  	}
  
  	public PeerField this[int i] {
  		get { return (PeerField)List[i]; }
  	}
  }
  
  class PeerMap {
  	public PeerMap () {
  		peers = new Hashtable ();
  	}
  
  	public void Add (Peer peer) {
  		Add (peer.CLRType, peer);
  	}
  
  	public void Add (Type clr_type, Peer peer) {
  		peers.Add (clr_type, peer);
  	}
  
  	public ICollection Peers {
  		get { return peers.Values; }
  	}
  
  	public Peer this[Type clr_type] {
  		get {
  			if (peers.Contains (clr_type))
  				return (Peer)peers[clr_type];
  
  			return null;
  		}
  	}
  
  	public Peer GetPeer (Type clr_type) {
  		Peer peer;
  
  		if (Peer.CLRIsValueType (clr_type)) {
  			peer = this[clr_type];
  			if (peer != null)
  				return peer;
  
  			if (Peer.CLRIsEnum (clr_type)) {
  				peer = this[Peer.CLRUnderlyingType (clr_type)];
  				if (peer != null)
  				return peer;
  
  				throw new ArgumentException ("Could not find peer or underlying peer for enum " + clr_type);
  			}
  			else
  				throw new ArgumentException ("Could not find peer for value type " + clr_type);
  		}
  		else {
  			Type type = clr_type;
  			while (type != null) {
  				peer = this[type];
  				if (peer != null)
  					return peer;
  
  				type = type.BaseType;
  			}
  
  			throw new ArgumentException ("Could not find peer for class " + clr_type);
  		}
  	}
  
  	public void ResolvePeers () {
  		BindingFlags binding =
  			BindingFlags.DeclaredOnly |
  			BindingFlags.Instance |
  			BindingFlags.NonPublic |
  			BindingFlags.Public;
  
  		// base type
  
  		foreach (Peer peer in Peers) {
  			if (peer.IsOpaque || peer.IsValueType || peer.CLRType.BaseType == null)
  				continue;
  
  			peer.NearestBase = GetPeer (peer.CLRType.BaseType);
  			if (peer.NearestBase == null) {
  				Console.Error.WriteLine ("Error: cannot find an internal base type for {0}.", peer.Name);
  				Environment.Exit (-1);
  			}
  		}
  
  		// fields
  
  		foreach (Peer peer in Peers) {
  			if (peer.IsOpaque || peer.IsEnum)
  				continue;
  
  			Type clr_base = null;
  			if (peer.NearestBase != null)
  				clr_base = peer.NearestBase.CLRType;
  
  			Stack declared = new Stack ();
  			Type type = peer.CLRType;
  
  			while (type != clr_base) {
  				declared.Push (type);
  				type = type.BaseType;
  			}
  
  			// build declared field list
  
  			while (declared.Count > 0) {
  
gt: 				type = (Type)declared.Pop ();