<repo_name>dewhisna/m6811dis<file_sep>/programs/m6811dis/memclass.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      MEMCLASS

      This is the C++ object definition for a Memory Object.  The Memory
      object is an object that encompasses the whole of defined memory to
      be used for file conversions, disassemblers, etc.

	  Author:  <NAME>
      Date:    January 28, 1997

      Written in: Borland C++ 4.52

      Updated: June 22, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

		Updated:	July 21, 1997 to expand TMemRange function base.

      Description:

         Each memory object represents the entire memory being acted upon,
      and typically, only one memory object needs to be created for an
      application.
         The memory is divided into pages (for paged memory applications)
      and each page has a descriptor byte that the application can use
      for processing -- useful for things such as "is_loaded", "is_data",
      "is_code", etc.

      Note:  All Addresses and All Block Numbers are ZERO ORIGINATED!
               Size numbers (such as NBlocks and BlockSize) are ONE ORIGINATED!

*/

#include "memclass.h"
#include "errmsgs.h"

#ifndef NULL
#define NULL 0
#endif

// The following are the function declarations for TMemRange

// TMemRange -- Constructor
//    The following constructs a TMemRange object by setting the StartAddr and
//    Size, and nullifying the next pointer.
TMemRange::TMemRange(unsigned long aStartAddr, unsigned long aSize, unsigned long aUserData)
{
   StartAddr = aStartAddr;
   Size = aSize;
	UserData = aUserData;
   Next=NULL;
}

// TMemRange -- Duplicating Constructor
//    This function is sorta like 'strdup'.  It creates a new MemRange object
//    and copies itself to it and then calls itself recursively to duplicate
//    the objects linked with the Next pointer.
//    Supports:   ERR_OUT_OF_MEMORY throwback
TMemRange::TMemRange(TMemRange& aRange)
{
   StartAddr=aRange.StartAddr;
   Size=aRange.Size;
	UserData=aRange.UserData;
   Next=NULL;

	try {
		if (aRange.Next!=NULL) {
      	Next=new TMemRange(*aRange.Next);
         if (Next==NULL) THROW_MEMORY_EXCEPTION_ERROR(0);
      }
   }
   catch (EXCEPTION_ERROR*) {
		PurgeRange();
      throw;
   }
}

// TMemRange -- Destructor
//    The following destructs a TMemRange object by checking to see if Next
//    points to a valid pointer to a linked list of MemRange Objects.  If it
//    does, it recursively destroys additionally allocated MemRange Objects.
TMemRange::~TMemRange(void)
{
   PurgeRange();
}

// TMemRange -- PurgeRange
//    The following destructs all children of the called range.  This
//    is useful in re-using (and re-initializing) existing TMemRange objects.
//    This function is used by the destructor to destroy children as well
//    when an object is removed.  The difference is that this function allows
//    us to destroy the children without killing the parent.
void TMemRange::PurgeRange(void)
{
	StartAddr = 0;
	Size = 0;
	UserData = 0;

   if (Next!=NULL) {
      delete Next;
      Next=NULL;
   }
}

// TMemRange -- AddressInRange
//    The following determines if a specified address exists within the
//    ranges specified by the current object (or its children).
//    This is useful for programs needing to identify addresses that are
//    in a range without necessarily needing to use descriptor bytes or
//    other methods of address referal.
//    The routine returns a '1' (or TRUE) if the address lies inside the
//    linked list of range (where this object is the head) or '0' (or
//    FALSE) if it does not.
int TMemRange::AddressInRange(unsigned long aAddr)
{
   if ((aAddr>=StartAddr) && (aAddr<(StartAddr+Size)))
      return(1);
   else if (Next!=NULL) return (Next->AddressInRange(aAddr));
   return (0);
}


// TMemRange -- Consolidate
//    The following function spans through the TMemRange and finds the
//    lowest and highest addresses.  It then purges the TMemRange and
//    sets its size and length to the corresponding values.
void TMemRange::Consolidate(void)
{
   unsigned long  MinAddr, MaxAddr;
   TMemRange      *aRange;

   MinAddr = StartAddr;
   MaxAddr = StartAddr+Size;

   aRange = Next;
   while (aRange) {
      if (aRange->StartAddr < MinAddr) MinAddr = aRange->StartAddr;
      if ((aRange->StartAddr+aRange->Size) > MaxAddr)
         MaxAddr = aRange->StartAddr+aRange->Size;
      aRange = aRange->Next;
   }
   PurgeRange();
   StartAddr = MinAddr;
   Size = MaxAddr - MinAddr;
}

// IsNullRange
//		The following function will test the range to see if it
//		is null and return a TRUE if it is or FALSE if not.  A
//		null range is defined as one whose size records are all
//		zero.
int TMemRange::IsNullRange(void)
{
	if (Size != 0) return 0;
	if (Next != NULL) return (Next->IsNullRange());
	return 1;
}

//	Invert
//		The following is the converse of Consolidate.  It transforms
//		the range list to its inverse within the bounds of the
//		given range.
//		Note: The UserData is lost from the original Range... (obviously)
//    Supports:   ERR_OUT_OF_MEMORY throwback
void TMemRange::Invert(void)
{
	TMemRange*	TempRange;
	TMemRange	NewRange(0, 0, 0);

	TMemRange*	ptRange;

	unsigned long	StartA;
	unsigned long	Ending;

	// Duplicate ourselves:
	try {
		TempRange = new TMemRange(*this);
	}
	catch (EXCEPTION_ERROR*) {
		throw;
	}

	// clean and sort the copy
	try {
		TempRange->Compact();
		TempRange->RemoveOverlaps();
		TempRange->Sort();
	}
	catch (EXCEPTION_ERROR*) {
		delete TempRange;
		throw;
	}

	// Get our bounds from the consolidated version
	Ending = 0;

	ptRange = TempRange;
	while (ptRange != NULL) {
		StartA = ptRange->StartAddr;

		if (StartA > Ending) {
			try {
				NewRange.AddRange(Ending, StartA-Ending);	// Add range between zones
			}
			catch (EXCEPTION_ERROR*) {
				delete TempRange;
				throw;
			}
		}
		Ending = StartA + ptRange->Size;			// Move Ending

		ptRange=ptRange->Next;
	}

	// Purge us and fill ourselves with the new inverted range
	PurgeRange();

	// Copy the new range structure to this range structure
	if (NewRange.Next != NULL) {
		// Copy the first record
		StartAddr = NewRange.Next->StartAddr;
		Size = NewRange.Next->Size;
		UserData = NewRange.Next->UserData;
		// And concatenate the rest
		try {
			Concatenate(NewRange.Next->Next);
		}
		catch (EXCEPTION_ERROR*) {
			throw;
		}
	}

	// Clean memory:
	NewRange.PurgeRange();
	TempRange->PurgeRange();
	delete TempRange;
}

//	Sort
//		The following sorts the range in ascending format.  Useful
//		for traversing, etc.  If two ranges have the same starting
//		address, then the shorter is placed ahead of the longer.
//		Since range lists are very short, we'll use a simple
//		bubble sort.
//    Supports:   ERR_OUT_OF_MEMORY throwback
void TMemRange::Sort(void)
{
	TMemRange	TempRange(0, 0, 0);
	TMemRange	Swap(0, 0, 0);

	TMemRange*	TempA;
	TMemRange*	TempB;
	TMemRange*	TempX;
	TMemRange*	TempY;
	unsigned long	StartA, EndA;
	unsigned long	StartB, EndB;
	int	Flag;

	try {
		TempRange.Concatenate(this);
	}
	catch (EXCEPTION_ERROR*) {
		throw;
	}

	TempA = &TempRange;
	TempB = TempA->Next;

	while (TempB != NULL) {
		TempX=TempB;
		TempY=TempB->Next;

		StartA = TempB->StartAddr;
		EndA = StartA+TempB->Size;
		Flag = 0;

		while ((!Flag) && (TempY != NULL)) {
			StartB = TempY->StartAddr;
			EndB = StartB+TempY->Size;

			if ( (StartB<StartA)  ||
				   ((StartB==StartA) && (EndB<EndA)) ) {
				Flag = 1;
			} else {
				TempX=TempX->Next;
				TempY=TempY->Next;
			}
		}

		if (!Flag) {
			// If none was found greater than this A/B pair, advance -- loop to end
			TempA=TempA->Next;
			TempB=TempB->Next;
		} else {
			// We found one, lets swap it
			Swap.StartAddr = TempY->StartAddr;
			Swap.Size = TempY->Size;
			Swap.UserData = TempY->UserData;
			TempY->StartAddr = TempB->StartAddr;
			TempY->Size = TempB->Size;
			TempY->UserData = TempB->UserData;
			TempB->StartAddr = Swap.StartAddr;
			TempB->Size = Swap.Size;
			TempB->UserData = Swap.UserData;
			// Reloop, but don't advance A/B pair -- this way all pairs are tested
		}
	}

	// Purge us and fill ourselves with the new sorted range
	PurgeRange();

	// Copy the new range structure to this range structure
	if (TempRange.Next != NULL) {
		// Copy the first record
		StartAddr = TempRange.Next->StartAddr;
		Size = TempRange.Next->Size;
		UserData = TempRange.Next->UserData;
		// And concatenate the rest
		try {
			Concatenate(TempRange.Next->Next);
		}
		catch (EXCEPTION_ERROR*) {
			throw;
		}
	}

	// Clean memory:
	TempRange.PurgeRange();
}

//	RemoveOverlaps
//		The following function traverses the range and removes
//		overlaps.  If overlaps exist, the offending range
//		entries are replaced by a single range spanning the same
//		total range.  Note that the order of the ranges will
//		change if overlaps exist and are not deterministic.
//		Also, the UserData value must be IDENTICAL on the
//		offending ranges, otherwise, they are not changed.
//    Supports:   ERR_OUT_OF_MEMORY throwback
void TMemRange::RemoveOverlaps(void)
{
	TMemRange	TempRange(0, 0, 0);

	TMemRange*	TempA;
	TMemRange*	TempB;
	TMemRange*	TempX;
	TMemRange*	TempY;
	unsigned long	StartA, EndA;
	unsigned long	StartB, EndB;
	int	Flag;

	try {
		TempRange.Concatenate(this);
	}
	catch (EXCEPTION_ERROR*) {
		throw;
	}

	TempA = &TempRange;
	TempB = TempA->Next;

	while (TempB != NULL) {
		TempX=TempB;
		TempY=TempB->Next;

		StartA = TempB->StartAddr;
		EndA = StartA+TempB->Size;
		Flag = 0;

		while ((!Flag) && (TempY != NULL)) {
			StartB = TempY->StartAddr;
			EndB = StartB+TempY->Size;

			if ((TempB->UserData == TempY->UserData) &&
			    ( ((StartA>=StartB) && (StartA<EndB)) ||
				   ((EndA>=StartB) && (EndA<EndB)) ) ) {
				Flag = 1;
			} else {
				TempX=TempX->Next;
				TempY=TempY->Next;
			}
		}

		if (!Flag) {
			// If no overlap with this A/B pair, advance -- continue till end
			TempA=TempA->Next;
			TempB=TempB->Next;
		} else {
			if (StartB<StartA) StartA=StartB;
			if (EndB>EndA) EndA=EndB;
			// Consolidate to remove overlap:
			TempB->StartAddr = StartA;
			TempB->Size = EndA-StartA;
			// Remove extraneous range:
			TempX->Next = TempY->Next;
			TempY->Next = NULL;		// Nullify to avoid false delete
			delete TempY;
			TempY = TempX->Next;
			// Reloop, but don't advance A/B pair -- this way all pairs are tested
		}
	}

	// Purge us and fill ourselves with the new compressed range
	PurgeRange();

	// Copy the new range structure to this range structure
	if (TempRange.Next != NULL) {
		// Copy the first record
		StartAddr = TempRange.Next->StartAddr;
		Size = TempRange.Next->Size;
		UserData = TempRange.Next->UserData;
		// And concatenate the rest
		try {
			Concatenate(TempRange.Next->Next);
		}
		catch (EXCEPTION_ERROR*) {
			throw;
		}
	}

	// Clean memory:
	TempRange.PurgeRange();
}

//	Compact
//		This function removes any size-zero entries within
//		the range, unless of course there is only one range (this one)
//		and it has a zero size.
void TMemRange::Compact(void)
{
	TMemRange*	TempA;
	TMemRange*	TempB;

	TempA = this;
	TempB = Next;
	while (TempB != NULL) {
		if (TempB->Size == 0) {
			TempA->Next = TempB->Next;
			TempB->Next = NULL;		// Nullify to avoid false delete
			delete TempB;
			TempB = TempA->Next;
		} else {
			TempA = TempA->Next;
			TempB = TempB->Next;
		}
	}
	// If this one is 0, and we have more after it, rotate data up
	if ((Size == 0) && (Next != NULL)) {
		TempA = Next;
		StartAddr = TempA->StartAddr;
		Size = TempA->Size;
		UserData = TempA->UserData;
		Next = TempA->Next;
		TempA->Next = NULL;			// Nullify to avoid false delete
		delete TempA;
	}
}

//	Concatenate
//		The following traverses the passed in range and appends
//		it to the end of this range.
//    Supports:   ERR_OUT_OF_MEMORY throwback
void TMemRange::Concatenate(TMemRange* aRange)
{
	TMemRange*	TempRange;

	TempRange = aRange;
	while (TempRange != NULL) {
		try {
			if (TempRange->Size != 0) {
				AddRange(TempRange->StartAddr, TempRange->Size,
												TempRange->UserData);
			}
		}
		catch (EXCEPTION_ERROR*) {
			throw;
		}
		TempRange = TempRange->Next;
	}
}

// GetStartAddr
//    This function returns the protected StartAddr element.
unsigned long TMemRange::GetStartAddr(void)
{
   return(StartAddr);
}

// SetStartAddr
//    This function sets the protected StartAddr element
void TMemRange::SetStartAddr(unsigned long aStartAddr)
{
   StartAddr=aStartAddr;
}

// GetSize
//    This function returns the protected Size element.
unsigned long TMemRange::GetSize(void)
{
   return(Size);
}

// SetSize
//    This function sets the protected Size element.
void TMemRange::SetSize(unsigned long aSize)
{
   Size=aSize;
}

// GetNext
//    Returns the next pointer
TMemRange *TMemRange::GetNext(void)
{
   return(Next);
}

// SetNext
//    Sets the next pointer
void TMemRange::SetNext(TMemRange *aNext)
{
   Next=aNext;
}

//	GetUserData
//		This function returns the user-set data.  User-set data
//	is just to allow additional storage for the user without
//	having to allocate additional ranges -- sorta like user
//	data in listboxes, etc.  Useful to correlate ranges with
//	other objects and events.
unsigned long TMemRange::GetUserData(void)
{
	return (UserData);
}

//	SetUserData
//		This function sets the user-set data. User-set data
//	is just to allow additional storage for the user without
//	having to allocate additional ranges -- sorta like user
//	data in listboxes, etc.  Useful to correlate ranges with
//	other objects and events.
void TMemRange::SetUserData(unsigned long aUserData)
{
	UserData = aUserData;
}

// AddRange
//    This function allocates a new Range object based on the passed
//    parameters and then follows through the chain of Nexts recursively
//    to add it to the TAIL.
//    Supports:   ERR_OUT_OF_MEMORY throwback
TMemRange *TMemRange::AddRange(unsigned long aStartAddr, unsigned long aSize, unsigned long aUserData)
{
   TMemRange         *RetVal;

   RetVal=NULL;
   if (Next!=NULL) {
      try {
         RetVal=Next->AddRange(aStartAddr, aSize, aUserData);
      }
      catch (EXCEPTION_ERROR*) {
         throw;
      }
   } else {
      RetVal=new TMemRange(aStartAddr, aSize, aUserData);
      if (RetVal!=NULL) {
         Next=RetVal;
      } else {
         THROW_MEMORY_EXCEPTION_ERROR(0);
      }
   }
   return(RetVal);
}


// The following are the function declarations for TMappingObject

// TMappingObject -- Constructor
//    The following constructs a TMappingObject by setting the LogicalAddr,
//    BlockNumber, and Physical Address, and nullifying the next pointer.
TMappingObject::TMappingObject(unsigned long ALogicalAddr, unsigned int ABlockNumber, unsigned long APhysAddr)
{
   LogicalAddr = ALogicalAddr;
   BlockNumber = ABlockNumber;
   PhysicalAddr = APhysAddr;
   Next=NULL;
}

// TMappingObject -- Duplication Constructor
//    Works sorta like 'strdup'.  It allocates memory for a new TMappingObject,
//    copies itself to the new object, and returns a pointer to the new one.
//    Also, this function is recursive -- if the object this function is called
//    for has a valid next pointer, it calls the Duplication Constructor with
//		the next to duplicate the nexts in the newly created object.
//    Supports:   ERR_OUT_OF_MEMORY throwback.
TMappingObject::TMappingObject(TMappingObject& aMap)
{
   LogicalAddr = aMap.LogicalAddr;
   BlockNumber = aMap.BlockNumber;
   PhysicalAddr = aMap.PhysicalAddr;
   Next=NULL;

   try {
		if (aMap.Next!=NULL) {
      	Next=new TMappingObject(*aMap.Next);
         if (Next==NULL) THROW_MEMORY_EXCEPTION_ERROR(0);
      }
   }
   catch (EXCEPTION_ERROR*) {
		if (Next!=NULL) {
			delete Next;
			Next=NULL;
		}
      throw;
   }
}

// TMappingObject -- Destructor
//    The following destructs a TMappingObject by checking to see if Next
//    points to a valid pointer to a linked list of MappingObjects.  If it
//    does, it recursively destroys additionally allocated MappingObjects.
TMappingObject::~TMappingObject(void)
{
   if (Next!=NULL) {
      delete Next;
      Next=NULL;
   }
}

// GetLogicalAddr
//    Returns the protected LogicalAddr element.
unsigned long TMappingObject::GetLogicalAddr(void)
{
   return LogicalAddr;
}

// GetBlockNumber
//    Returns the protected BlockNumber element.
unsigned int TMappingObject::GetBlockNumber(void)
{
   return BlockNumber;
}

// GetPhysicalAddr
//    Returns the protected PhysicalAddr element.
unsigned long TMappingObject::GetPhysicalAddr(void)
{
   return PhysicalAddr;
}

// SetNext
//    Sets the Next pointer.
void TMappingObject::SetNext(TMappingObject *ANext)
{
   Next = ANext;
}

// GetNext
//    Returns the protected Next pointer element.
TMappingObject *TMappingObject::GetNext(void)
{
   return Next;
}


// AddMapping
//    This function allocates a new TMappingObject based on the passed
//    parameters and then follows through the chain of Nexts recursively
//    to add it to the TAIL.
//    Supports:   ERR_OUT_OF_MEMORY throwback
TMappingObject *TMappingObject::AddMapping(unsigned long ALogicalAddr, unsigned int ABlockNumber, unsigned long APhysAddr)
{
   TMappingObject    *RetVal;

   RetVal=NULL;
   if (Next!=NULL) {
      try {
         RetVal=Next->AddMapping(ALogicalAddr, ABlockNumber, APhysAddr);
      }
      catch (EXCEPTION_ERROR*) {
         throw;
      }
   } else {
      RetVal=new TMappingObject(ALogicalAddr, ABlockNumber, APhysAddr);
      if (RetVal!=NULL) {
         Next=RetVal;
      } else {
         THROW_MEMORY_EXCEPTION_ERROR(0);
      }
   }
   return(RetVal);
}


// The following are the function declarations for TMemObject

// TMemObject -- Constructor
//    The following constructs a TMemObject by setting NumBlocks and BlockSize,
//    allocates the necessary memory for the object, and calls ClearMemory to
//    set all memory elements to FillByte with a descriptor of 0.  And it
//    nullifies the BlockMap pointer.
//    Supports:   ERR_OUT_OF_MEMORY throwback.
TMemObject::TMemObject(unsigned int NBlocks, unsigned long BSize, unsigned char FillByte, int UseDesc)
{
   try {
      CreateMemObject(NBlocks, BSize, FillByte, UseDesc);
   }
   catch (EXCEPTION_ERROR*) {
      throw;
   }
}

// TMemObject -- Duplicating Constructor
//    Works sorta like 'strdup'.  It allocates memory for a new TMemObject,
//    copies itself to the new object, and returns a pointer to the new one.
//    If BlockMap is a valid BlockMap pointer, it calls the MappingObject
//		Duplicating Contructor to duplicate the mapping as well.
//    Supports:   ERR_OUT_OF_MEMORY throwback.
TMemObject::TMemObject(TMemObject& aMem)
{
   unsigned long i;

   try {
      CreateMemObject(aMem.NumBlocks, aMem.BlockSize, 0x00,
            ((aMem.Descriptors!=NULL) ? 1 : 0));
   }
   catch (EXCEPTION_ERROR*) {
      throw;
   }

   for (i=0; (i<GetMemSize()); ++i) {
      if (aMem.Data)
   		Data[i]=aMem.Data[i];
      if (aMem.Descriptors)
         Descriptors[i]=aMem.Descriptors[i];
   }

   try {
      if (aMem.BlockMap!=NULL) BlockMap=new TMappingObject(*aMem.BlockMap);
   }
   catch (EXCEPTION_ERROR*) {
		// Cleanup on error
	   ClearMapping();              // Dispose of all mapping objects
	   if (Descriptors) delete[] Descriptors;		// Free Allocated memory
	   if (Data) delete[] Data;
      throw;
   }
}


// TMemObject -- Constructor From Range
//    This constructor creates a copy of the passed in range,
//    consolidates it to find the actual bounds of the range,
//    and then creates a Memory Object capable of holding
//    the entire range.  The Memory Object will consist of
//    a single block of the calculated size and a mapping
//    object will be created and attached to the memory
//    in accordance with the range.
TMemObject::TMemObject(TMemRange& aRange, unsigned char FillByte, int UseDesc)
{
   TMemRange         *TempRange;

   try {
      TempRange = new TMemRange(aRange);
   }
   catch (EXCEPTION_ERROR*) {
      throw;
   }

   if (TempRange) {
      TempRange->Consolidate();
      try {
         // Create the memory and setup the mapping
         CreateMemObject(1,TempRange->GetSize(), FillByte, UseDesc);
      }
      catch (EXCEPTION_ERROR*) {
			// Cleanup on error
			delete TempRange;
         throw;
      }
		try {
         AddMapping(TempRange->GetStartAddr(), 0, TempRange->GetStartAddr());
		}
		catch (EXCEPTION_ERROR*) {
			// Cleanup if we encounter an error
		   ClearMapping();               // Dispose of all mapping objects
		   if (Descriptors) delete[] Descriptors;		// Free Allocated memory
		   if (Data) delete[] Data;
			throw;
		}
   }

   delete TempRange;
}

// TMemObject -- Destructor
//    The following destructs a TMemObject by calling ClearMapping to
//    destroy all associated mapping objects and then it frees all memory
//    allocated for the memory object.
TMemObject::~TMemObject(void)
{
   ClearMapping();               // Dispose of all mapping objects
   if (Descriptors) delete[] Descriptors;		// Free Allocated memory
   if (Data) delete[] Data;
}

// CreateMemObject
//    This function creates a TMemObject by allocating and initializing
//    necessary memory.  It is here in its own function so that all the
//    various overloaded constructors can call it.
void TMemObject::CreateMemObject(unsigned int NBlocks, unsigned long BSize, unsigned char FillByte, int UseDesc)
{
   Data = new unsigned char[NBlocks*BSize];
   if (Data == NULL) THROW_MEMORY_EXCEPTION_ERROR(0);     // Report Error if out of memory
   if (UseDesc) {
	  Descriptors = new unsigned char[NBlocks*BSize];
      if (Descriptors == NULL) {
         delete[] Data;
         THROW_MEMORY_EXCEPTION_ERROR(0);		// Report Error if out of memory
      }
   } else Descriptors = NULL;
   NumBlocks=NBlocks;
   BlockSize=BSize;
   BlockMap=NULL;
   ClearMemory(FillByte);
}

// GetByte
//    Returns the memory data byte addressed by the passed in Logical Address,
//    based on the current Block Mapping.
unsigned char TMemObject::GetByte(unsigned long LogicalAddr)
{
   TMappingObject *Temp_Ptr;

   if (Data) {
      Temp_Ptr = BlockMap;
      while (Temp_Ptr != NULL) {
         if ((LogicalAddr>=Temp_Ptr->GetLogicalAddr()) &&
             (LogicalAddr<(Temp_Ptr->GetLogicalAddr()+BlockSize))) {
            return (Data[(LogicalAddr-Temp_Ptr->GetLogicalAddr())+(Temp_Ptr->GetBlockNumber()*BlockSize)]);
         }
         Temp_Ptr=Temp_Ptr->GetNext();
      }
   }
   return (0);
}

// SetByte
//    Sets the memory data byte addressed by the passed in Logical Address,
//    based on the current Block Mapping to the passed in Byte.
int TMemObject::SetByte(unsigned long LogicalAddr, unsigned char Byte)
{
   TMappingObject *Temp_Ptr;

   if (Data) {
      Temp_Ptr = BlockMap;
      while (Temp_Ptr != NULL) {
         if ((LogicalAddr>=Temp_Ptr->GetLogicalAddr()) &&
             (LogicalAddr<(Temp_Ptr->GetLogicalAddr()+BlockSize))) {
            Data[(LogicalAddr-Temp_Ptr->GetLogicalAddr())+(Temp_Ptr->GetBlockNumber()*BlockSize)]=Byte;
            return(1);
         }
         Temp_Ptr=Temp_Ptr->GetNext();
      }
   }
   return(0);
}

// GetDescriptor
//    Returns the memory descriptor byte addressed by the passed in Logical Address,
//    based on the current Block Mapping.
unsigned char TMemObject::GetDescriptor(unsigned long LogicalAddr)
{
   TMappingObject *Temp_Ptr;

   if (Descriptors) {
      Temp_Ptr = BlockMap;
      while (Temp_Ptr != NULL) {
         if ((LogicalAddr>=Temp_Ptr->GetLogicalAddr()) &&
             (LogicalAddr<(Temp_Ptr->GetLogicalAddr()+BlockSize))) {
            return (Descriptors[(LogicalAddr-Temp_Ptr->GetLogicalAddr())+(Temp_Ptr->GetBlockNumber()*BlockSize)]);
         }
         Temp_Ptr=Temp_Ptr->GetNext();
      }
   }
   return (0);
}

// SetDescriptor
//    Sets the memory descriptor byte addressed by the passed in Logical Address,
//    based on the current Block Mapping to the passed in Desc.
int TMemObject::SetDescriptor(unsigned long LogicalAddr, unsigned char Desc)
{
   TMappingObject *Temp_Ptr;

   if (Descriptors) {
      Temp_Ptr = BlockMap;
      while (Temp_Ptr != NULL) {
         if ((LogicalAddr>=Temp_Ptr->GetLogicalAddr()) &&
             (LogicalAddr<(Temp_Ptr->GetLogicalAddr()+BlockSize))) {
            Descriptors[(LogicalAddr-Temp_Ptr->GetLogicalAddr())+(Temp_Ptr->GetBlockNumber()*BlockSize)]=Desc;
            return(1);
         }
         Temp_Ptr=Temp_Ptr->GetNext();
      }
   }
   return(0);
}

// GetMemSize
//    Returns the size of the memory allocated for data bytes.
unsigned long TMemObject::GetMemSize(void)
{
   return(NumBlocks*BlockSize);
}

// ClearMemory
//    Sets all allocated data bytes to the specified FillByte and sets
//    all corresponding descriptor bytes to 0.
void TMemObject::ClearMemory(unsigned char FillByte)
{
   unsigned long i;

   for (i=0; (i<GetMemSize()); ++i) {
      if (Data)
         Data[i]=FillByte;
      if (Descriptors)
         Descriptors[i]=0;
   }
}

// ClearMapping
//    If BlockMap is not NULL, it destroys the object (and its child
//    objects) that it points to, and sets BlockMap to NULL.
void TMemObject::ClearMapping(void)
{
   if (BlockMap != NULL) {
      delete BlockMap;
      BlockMap=NULL;
   }
}

// AddMapping
//    Adds a mapping object at the TAIL of the BlockMap IF the defined object
//    is within range of the allocated Memory space.
//    Supports:   ERR_OUT_OF_MEMORY throwback
//                ERR_OUT_OF_RANGE throwback (IF MAPTHROW is defined)
//                ERR_MAPPING_OVERLAP throwback (IF MAPTHROW is defined)
void TMemObject::AddMapping(unsigned long ALogicalAddr, unsigned int ABlockNumber, unsigned long APhysAddr)
{
   TMappingObject *Temp_Ptr;

#ifdef MAPTHROW
   if (ABlockNumber>=NumBlocks) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_OUT_OF_RANGE, 0, "");
#endif
   if (ABlockNumber>=NumBlocks) return;
#ifdef MAPTHROW
   Temp_Ptr = BlockMap;
   while (Temp_Ptr != NULL) {
      if ((ALogicalAddr>=Temp_Ptr->GetLogicalAddr()) &&
          (ALogicalAddr<(Temp_Ptr->GetLogicalAddr()+BlockSize))) {
          break;
      }
      Temp_Ptr=Temp_Ptr->GetNext();
   }
   if (Temp_Ptr != NULL) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_MAPPING_OVERLAP, 0, "");
#endif
   if (BlockMap==NULL) {
      Temp_Ptr = new TMappingObject(ALogicalAddr, ABlockNumber, APhysAddr);
      if (Temp_Ptr == NULL) THROW_MEMORY_EXCEPTION_ERROR(0);    // Return error if no memory
      BlockMap=Temp_Ptr;
   } else {
      try {
         BlockMap->AddMapping(ALogicalAddr, ABlockNumber, APhysAddr);
      }
      catch (EXCEPTION_ERROR*) {
         throw;
      }
   }
}

// GetPhysicalAddr
//    Looks the LogicalAddr up in the defined BlockMap and returns the
//    equivalent PhysicalAddr.
unsigned long TMemObject::GetPhysicalAddr(unsigned long LogicalAddr)
{
   TMappingObject *Temp_Ptr;

   Temp_Ptr = BlockMap;
   while (Temp_Ptr != NULL) {
      if ((LogicalAddr>=Temp_Ptr->GetLogicalAddr()) &&
          (LogicalAddr<(Temp_Ptr->GetLogicalAddr()+BlockSize))) {
         return (Temp_Ptr->GetPhysicalAddr()+(LogicalAddr-Temp_Ptr->GetLogicalAddr()));
      }
      Temp_Ptr=Temp_Ptr->GetNext();
   }
   return (0x0000);
}

<file_sep>/programs/m6811dis/memclass.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      MEMCLASS

      This is the C++ Memory Object Class Header File.

	  Author:  <NAME>
      Date:    January 28, 1997

      Written in: Borland C++ 4.52

      Updated: June 22, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

		Updated:	July 21, 1997 to expand TMemRange function base.

*/

#ifndef MEMCLASS_H
#define MEMCLASS_H

#include "errmsgs.h"

class TMemRange {
protected:
   unsigned long  StartAddr;
   unsigned long  Size;
	unsigned long	UserData;
   TMemRange *Next;

public:
   TMemRange(unsigned long aStartAddr, unsigned long aSize, unsigned long aUserData = 0);
   TMemRange(TMemRange& aRange);
   virtual ~TMemRange(void);
   void PurgeRange(void);
   int AddressInRange(unsigned long aAddr);
   void Consolidate(void);
	int IsNullRange(void);
	void Invert(void);
	void Sort(void);
	void RemoveOverlaps(void);
	void Compact(void);
	void Concatenate(TMemRange* aRange);
   unsigned long GetStartAddr(void);
   void SetStartAddr(unsigned long aStartAddr);
   unsigned long GetSize(void);
   void SetSize(unsigned long aSize);
   TMemRange *GetNext(void);
   void SetNext(TMemRange *aNext);
	unsigned long GetUserData(void);
	void SetUserData(unsigned long aUserData);
   TMemRange *AddRange(unsigned long aStartAddr, unsigned long aSize, unsigned long aUserData = 0);
};


class TMappingObject {
protected:
   unsigned long LogicalAddr;
   unsigned int BlockNumber;
   unsigned long PhysicalAddr;
   TMappingObject *Next;

public:
   TMappingObject(unsigned long ALogicalAddr, unsigned int ABlockNumber, unsigned long APhysAddr);
   TMappingObject(TMappingObject& aMap);
   virtual ~TMappingObject(void);
   unsigned long GetLogicalAddr(void);
   unsigned int GetBlockNumber(void);
   unsigned long GetPhysicalAddr(void);
   void SetNext(TMappingObject *ANext);
   TMappingObject *GetNext(void);
   TMappingObject *AddMapping(unsigned long ALogicalAddr, unsigned int ABlockNumber, unsigned long APhysAddr);
};


class TMemObject {
protected:
   unsigned int NumBlocks;
   unsigned long BlockSize;

   unsigned char *Data;
   unsigned char *Descriptors;

   TMappingObject *BlockMap;

public:
   TMemObject(unsigned int NBlocks, unsigned long BSize, unsigned char FillByte, int UseDesc);
   TMemObject(TMemObject& aMem);
   TMemObject(TMemRange& aRange, unsigned char FillByte, int UseDesc);
   virtual ~TMemObject(void);
   unsigned char GetByte(unsigned long LogicalAddr);
   int SetByte(unsigned long LogicalAddr, unsigned char Byte);
   unsigned char GetDescriptor(unsigned long LogicalAddr);
   int SetDescriptor(unsigned long LogicalAddr, unsigned char Desc);
   unsigned long GetMemSize(void);
   void ClearMemory(unsigned char FillByte);
   void ClearMapping(void);
   void AddMapping(unsigned long ALogicalAddr, unsigned int ABlockNumber, unsigned long APhysAddr);
   unsigned long GetPhysicalAddr(unsigned long LogicalAddr);

private:
   void CreateMemObject(unsigned int NBlocks, unsigned long BSize, unsigned char FillByte, int UseDesc);
};

#endif	// MEMCLASS_H

<file_sep>/programs/dist/linux/m6811dis/readme.txt
The Linux version of M6811DIS was compiled against LSB
(Linux Standard Base).  To guarantee runability, install
LSB:
sudo apt-get install lsb
<file_sep>/programs/funcanal/funcanal.h
// funcanal.h : Application header file
//
// $Log: funcanal.h,v $
// Revision 1.1  2002/07/01 05:50:00  dewhisna
// Initial Revision
//
//

#if !defined(AFX_FUNCANAL_H__EBA8556D_010B_4CA0_AAC4_8E188F312700__INCLUDED_)
#define AFX_FUNCANAL_H__EBA8556D_010B_4CA0_AAC4_8E188F312700__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "resource.h"


#endif // !defined(AFX_FUNCANAL_H__EBA8556D_010B_4CA0_AAC4_8E188F312700__INCLUDED_)
<file_sep>/programs/m6811dis/m6811dis.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//
//	Original Written in Turbo Pascal V7.0
//	Ported to MS Visual C++ 5.0/6.0
//  This version ported to GCC to be platform independent
//
//	1.0 Initial release
//
//	1.1 "Spit" version --- created August 28, 1997 by <NAME>
//	This version has the new "SPIT" command added to the .CTL
//	file parsing to enable/disable code-seeking.  Also, the .OP
//	file was done away with and the file-io bugs and index ranges
//	were fixed.
//
// 	1.2 Translated code from Pascal to C++ to allow for easy expansion
//	of label size and number of labels.  Added in support from m6811dm
//	for multiple input modules.  Control files from previous versions
//	are backward compatible (except for special m6811dm compile)...
//	The only thing not compatible with the old version control files
//	is that on the old version if no entry or indirect values were
//	specified, the file load addressed was used.  On this version, the
//	default behavior of the control file parser is to issue an error
//	if there are no entry points or code-indirects specified.  This is
//	necessary because the true load address isn't necessarily known
//	because of file loading and offsetting is handled exclusively by
//	DFC libraries.
//

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include "m6811dis.h"

#include "m6811gdc.h"


int main(int argc, char *argv[])
{
	bool OkFlag;
	int Count;

	CM6811Disassembler	theDisassembler;

	printf("M6811 Disassembler V%ld.%02ld -- GDC V%ld.%02ld\n",	(theDisassembler.GetVersionNumber()&0x0000FF00ul)>>8,
																(theDisassembler.GetVersionNumber()&0x000000FFul),
																(theDisassembler.GetVersionNumber()&0xFF000000ul)>>24,
																(theDisassembler.GetVersionNumber()&0x00FF0000ul)>>16);
	printf("Copyright(c)1996-2014 by <NAME>\n");
	printf("\n");
	if (argc<2) {
		printf("Usage: m6811dis <ctrl filename1> [<ctrl filename2> <ctrl filename3> ...]\n");
		return -1;
	}

	OkFlag = true;
	Count = 1;
	while ((OkFlag) && (Count < argc)) {
		ifstreamControlFile CtrlFile(argv[Count]);
		if (!CtrlFile.is_open()) {
			printf("*** Error: Opening control file \"%s\" for reading...\n", argv[Count]);
			return -2;
		}
		OkFlag = theDisassembler.ReadControlFile(CtrlFile, (Count == argc-1), &std::cout, &std::cerr);
		CtrlFile.close();
		Count++;
	}

	if (OkFlag) theDisassembler.Disassemble(&std::cout, &std::cerr);

	return 0;
}
<file_sep>/programs/m6811dis/bindfc.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      BINARYDFC --- BINARY Data File Converter Class

      This is the C++ Module that contains routines to read and write binary
      data files, by defining a new derived class DFC_BINARY from the base
      class DataFileConverter.  This module makes use of the MEMCLASS type for
      memory interface.

	  Author:  <NAME>
      Date:    March 7, 1997

      Written in: Borland C++ 4.52

      Updated: June 23, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

      Updated: June 29, 1997 to use iostream instead of run-time
            library so that external DLL calls will function
            correctly.
*/

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <time.h>
#include "bindfc.h"


// RetrieveFileMapping:
//
//    This function reads in an already opened BINARY file pointed to by
//    'aFile' and generates a TMemRange object that encapsulates the file's
//    contents, offsetted by 'NewBase' (allowing loading of different files
//    to different base addresses).
//
// Author:  <NAME>
// Date:    June 28, 1997
int TDFC_Binary::RetrieveFileMapping(std::istream *aFile, unsigned long NewBase, TMemRange *aRange) const
{
	if (aRange) {
		aRange->PurgeRange();
		aRange->SetStartAddr(NewBase);
		aFile->seekg(0L, std::ios_base::end);
		aRange->SetSize(aFile->tellg());
		if (aRange->GetSize() == static_cast<unsigned long>(-1))
			aRange->SetSize(0);
		aFile->seekg(0L, std::ios_base::beg);
	}
   return 1;
}


// ReadDataFile:
//
//    This function reads in an already opened BINARY file pointed to by
//    'aFile' into the MemObject pointed to by 'aMemory' offsetted by
//    'NewBase' (allowing loading of different files to different base
//    address and setting the corresponding Memory Descriptors to 'aDesc'...
//
// Author:  <NAME>
// Date:    March 7, 1997
int TDFC_Binary::ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, unsigned char aDesc) const
{
	int            RetVal;           // Return Value
	unsigned char  aByte;

	unsigned long  CurrAddr;         // Current Memory Address

	RetVal=1;

	CurrAddr = NewBase;
	aFile->seekg(0L, std::ios_base::beg);
	while ((!aFile->eof()) && (aFile->peek() != EOF) && (aFile->good())) {
		aByte = aFile->get();
		if (!aMemory->SetByte(CurrAddr, aByte)) {
			THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_OVERFLOW, 0, "");
		}
		if (aMemory->GetDescriptor(CurrAddr)!=0) RetVal=0;
		aMemory->SetDescriptor(CurrAddr, aDesc);
		CurrAddr++;
	}

	return(RetVal);
}


// WriteDataFile:
//
//    This function writes to an already opened BINARY file pointed to by
//    'aFile' from the MemObject pointed to by 'aMemory' and whose Descriptor
//    has a match specified by 'aDesc'.  Matching is done by 'anding' the
//    aDesc value with the descriptor in memory.  If the result is non-zero,
//    the location is written.  Unless, aDesc=0, in which case ALL locations
//    are written regardless of the actual descriptor.  If the aDesc validator
//    computes out as false, then the data is filled according to the FillMode.
//
// Author:  <NAME>
// Date:    January 29, 1997
int TDFC_Binary::WriteDataFile(std::ostream *aFile, TMemRange *aRange, unsigned long NewBase, TMemObject *aMemory,
					 unsigned char aDesc, int UsePhysicalAddr, unsigned int FillMode) const
{
   TMemRange      *CurrRange;       // Range Spanning variable
   int            RetVal;           // Return Value
   unsigned long  BytesLeft;        // Remaining number of bytes to check/write
   unsigned long  CurrAddr;         // Current Logical Memory Address
   unsigned long  RealAddr = 0;     // Current Written Address equivalent
   int            NeedNewOffset;


   srand( (unsigned)time( NULL ) );

   CurrRange=aRange;
   RetVal=1;
   NeedNewOffset = 1;
   while (CurrRange!=NULL) {
      CurrAddr=CurrRange->GetStartAddr();
      BytesLeft=CurrRange->GetSize();

      while (BytesLeft) {
         while (BytesLeft && NeedNewOffset) {
            if ((aDesc==0) || (aDesc & aMemory->GetDescriptor(CurrAddr)) || (FillMode!=DFC_FILL_TYPE(NO_FILL))) {
               if (UsePhysicalAddr) {
                  RealAddr=aMemory->GetPhysicalAddr(CurrAddr)+NewBase;
               } else {
                  RealAddr=CurrAddr+NewBase;
               }
               NeedNewOffset=0;
            } else {
               BytesLeft--;
               CurrAddr++;
            }
         }

         while (BytesLeft && !NeedNewOffset) {
            if ((aDesc==0) || (aDesc & aMemory->GetDescriptor(CurrAddr))) {
               aFile->put(aMemory->GetByte(CurrAddr));
               if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0, "");
            } else {
               switch GET_DFC_FILL_TYPE(FillMode) {
                  case DFC_FILL_TYPE(ALWAYS_FILL_WITH):
                  case DFC_FILL_TYPE(CONDITIONAL_FILL_WITH):
                           aFile->put(GET_DFC_FILL_BYTE(FillMode));
                           if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0, "");
                           break;
                  case DFC_FILL_TYPE(ALWAYS_FILL_WITH_RANDOM):
                  case DFC_FILL_TYPE(CONDITIONAL_FILL_WITH_RANDOM):
                           aFile->put((unsigned char)(rand()%256));
                           if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0, "");
                           break;
                  default: aFile->put((unsigned char)0x00);
                           if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0, "");
                           break;
               }
            }

            BytesLeft--;
            CurrAddr++;
            RealAddr++;
            if ((aDesc==0) || (aDesc & aMemory->GetDescriptor(CurrAddr)) || (FillMode!=DFC_FILL_TYPE(NO_FILL))) {
               if (UsePhysicalAddr) {
                  if (RealAddr!=(aMemory->GetPhysicalAddr(CurrAddr)+NewBase)) {
                     NeedNewOffset=1;
                  }
               }
            } else {
               NeedNewOffset=1;
            }
         }
      }

      CurrRange=CurrRange->GetNext();
   }

   return(RetVal);
}

<file_sep>/programs/funcanal/FuncView/FuncViewPrjDoc.cpp
// FuncViewPrjDoc.cpp : implementation of the CFuncViewPrjDoc class
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncViewPrjDoc.cpp,v $
// Revision 1.1  2003/09/13 05:45:44  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "ProgDlg.h"

#include "MainFrm.h"
#include "FuncViewPrjDoc.h"			// Project Document View -- ChildFrame
#include "ChildFrm2.h"				// Func Diff View -- ChildFrame2
#include "FuncListView.h"
#include "ChildFrm3.h"				// Symbol Map View -- ChildFrame3
#include "ChildFrm4.h"				// Output View -- ChildFrame4
#include "OutputView.h"
#include "ChildFrm5.h"				// Comp Matrix View -- ChildFrame5
#include "ChildFrm6.h"				// Comp Diff Edit View -- ChildFrame6

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static const char *m_arrstrFileSetSectionNames[CFuncViewPrjDoc::FVFS_COUNT] =
{ "LeftFiles", "RightFiles" };

static const char *m_strMatrixSectionName = "MatrixFiles";

static const char m_strNumFilesEntry[] = "NumFiles";
static const char m_strFileEntryPrefix[] = "File";


/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc

IMPLEMENT_DYNCREATE(CFuncViewPrjDoc, CDocument)

BEGIN_MESSAGE_MAP(CFuncViewPrjDoc, CDocument)
	//{{AFX_MSG_MAP(CFuncViewPrjDoc)
	ON_COMMAND(ID_VIEW_FUNC_DIFF, OnViewFuncDiff)
	ON_UPDATE_COMMAND_UI(ID_VIEW_FUNC_DIFF, OnUpdateViewFuncDiff)
	ON_COMMAND(ID_SYMBOLS_RESET, OnSymbolsReset)
	ON_COMMAND(ID_VIEW_SYMBOL_MAP, OnViewSymbolMap)
	ON_UPDATE_COMMAND_UI(ID_VIEW_SYMBOL_MAP, OnUpdateViewSymbolMap)
	ON_COMMAND(ID_VIEW_OUTPUT_WINDOW, OnViewOutputWindow)
	ON_UPDATE_COMMAND_UI(ID_VIEW_OUTPUT_WINDOW, OnUpdateViewOutputWindow)
	ON_COMMAND(ID_VIEW_COMP_MATRIX, OnViewCompMatrix)
	ON_UPDATE_COMMAND_UI(ID_VIEW_COMP_MATRIX, OnUpdateViewCompMatrix)
	ON_COMMAND(ID_MATRIX_REBUILD, OnMatrixRebuild)
	ON_COMMAND(ID_MATRIX_REBUILD_FORCE, OnMatrixRebuildForce)
	ON_COMMAND(ID_SYMBOLS_EXPORT, OnSymbolsExport)
	ON_UPDATE_COMMAND_UI(ID_SYMBOLS_EXPORT, OnUpdateSymbolsExport)
	ON_COMMAND(ID_VIEW_COMP_DIFF, OnViewCompDiff)
	ON_UPDATE_COMMAND_UI(ID_VIEW_COMP_DIFF, OnUpdateViewCompDiff)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc construction/destruction

CFuncViewPrjDoc::CFuncViewPrjDoc()
{
	m_bFileOpenInProgress = FALSE;

	m_nMatrixRowCount = 0;
	m_nMatrixColCount = 0;
	m_ppnMatrix = NULL;
}

CFuncViewPrjDoc::~CFuncViewPrjDoc()
{
	FreeMatrixMemory();
}

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc callbacks

BOOL CALLBACK CFuncViewPrjDoc::FuncDescFileProgressCallback(int nProgressPos,
									int nProgressMax, BOOL bAllowCancel, LPARAM lParam)
{
	CFuncViewPrjDoc *pDoc = (CFuncViewPrjDoc*)lParam;
	ASSERT_VALID(pDoc);

	MSG msg;
	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);  
	}

	return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc serialization

void CFuncViewPrjDoc::Serialize(CArchive& ar)
{
	ASSERT(FALSE);			// This function isn't used -- OnOpenDocument and OnSaveDocument are used instead

	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc diagnostics

#ifdef _DEBUG
void CFuncViewPrjDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CFuncViewPrjDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc commands

BOOL CFuncViewPrjDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}

void CFuncViewPrjDoc::DeleteContents() 
{
	int i;

	for (i=0; i<GetFileSetCount(); i++) {
		m_arrFileSets[i].DeleteContents();
	}
	m_objSymbolMap.FreeAll();

	m_mapLeftToRightFunc.RemoveAll();
	m_mapRightToLeftFunc.RemoveAll();

	m_strCompDiffText = "";

	m_strOutputText = "";

	SetMatrixPathName("", TRUE);

	CDocument::DeleteContents();
}

BOOL CFuncViewPrjDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
	if (IsModified())
		TRACE0("Warning: OnOpenDocument replaces an unsaved document.\n");

	CFileException fe;
	CFile* pFile = GetFile(lpszPathName,
		CFile::modeRead|CFile::shareDenyWrite, &fe);
	if (pFile == NULL)
	{
		ReportSaveLoadException(lpszPathName, &fe,
			FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
		return FALSE;
	}
	pFile->Close();
	delete pFile;

	DeleteContents();
	SetModifiedFlag();  // dirty during de-serialize

	m_bFileOpenInProgress = TRUE;

	OnViewOutputWindow();

	CChildFrame4 *pFrame = (CChildFrame4 *)FindFrame(RUNTIME_CLASS(CChildFrame4));
	COutputView *pOutputView = NULL;
	COutputViewFile *pOutputViewFile = NULL;
	if (pFrame) pOutputView = pFrame->m_pOutputView;
	if (pOutputView) pOutputViewFile = pOutputView->GetOutputFile();

	if (pFrame) pFrame->BeginModalState();			// Put it in modal state during reading

	int i;
	int ndx;
	CString strTemp;
	CString strTemp2;
	LPTSTR pBuffer;
	int nCount;

	for (ndx = 0; ndx < GetFileSetCount(); ndx++) {
		nCount = ::GetPrivateProfileInt(m_arrstrFileSetSectionNames[ndx], m_strNumFilesEntry, 0, lpszPathName);
		for (i=0; i<nCount; i++) {
			strTemp.Format("%s%ld", LPCTSTR(m_strFileEntryPrefix), i);
			pBuffer = strTemp2.GetBuffer(1024);
			::GetPrivateProfileString(m_arrstrFileSetSectionNames[ndx], strTemp, _T(""), pBuffer, 1024, lpszPathName);
			strTemp2.ReleaseBuffer();
			AddFile(ndx, strTemp2, pOutputViewFile, pOutputViewFile);
		}
	}

	// Currently, only support 1 matrix file:
	strTemp.Format("%s0", LPCTSTR(m_strFileEntryPrefix));
	pBuffer = strTemp2.GetBuffer(1024);
	::GetPrivateProfileString(m_strMatrixSectionName, strTemp, _T(""), pBuffer, 1024, lpszPathName);
	strTemp2.ReleaseBuffer();
	SetMatrixPathName(strTemp2, TRUE);

	SetModifiedFlag(FALSE);     // start off with unmodified

	if (pFrame) pFrame->EndModalState();			// Exit modal state for that window
	if (pOutputViewFile) pOutputViewFile->Close();

	m_bFileOpenInProgress = FALSE;

	return TRUE;
}

BOOL CFuncViewPrjDoc::OnSaveDocument(LPCTSTR lpszPathName) 
{
	CFileException fe;
	CFile* pFile = NULL;
	pFile = GetFile(lpszPathName, CFile::modeCreate |
		CFile::modeReadWrite | CFile::shareExclusive, &fe);
	if (pFile == NULL)
	{
		ReportSaveLoadException(lpszPathName, &fe,
			TRUE, AFX_IDP_INVALID_FILENAME);
		return FALSE;
	}
	pFile->Close();

	int i;
	int ndx;
	CString strTemp;
	int nCount;

	for (ndx = 0; ndx < GetFileSetCount(); ndx++) {
		nCount = GetFileCount(ndx);
		strTemp.Format("%ld", nCount);
		::WritePrivateProfileString(m_arrstrFileSetSectionNames[ndx], m_strNumFilesEntry, strTemp, lpszPathName);
		for (i=0; i<nCount; i++) {
			strTemp.Format("%s%ld", LPCTSTR(m_strFileEntryPrefix), i);
			::WritePrivateProfileString(m_arrstrFileSetSectionNames[ndx], strTemp, GetFilePathName(ndx, i), lpszPathName);
		}
	}

	// Currently, only support 1 matrix file:
	strTemp.Format("%s0", LPCTSTR(m_strFileEntryPrefix));
	::WritePrivateProfileString(m_strMatrixSectionName, strTemp, GetMatrixPathName(), lpszPathName);

	SetModifiedFlag(FALSE);     // back to unmodified

	return TRUE;        // success
}

CString CFuncViewPrjDoc::GetFileSetDescription(int nFileSet)
{
	switch (nFileSet) {
		case FVFS_LEFT_FILES:
			return "Left-Hand Function Definition Files";

		case FVFS_RIGHT_FILES:
			return "Right-Hand Function Definition Files";
	}

	return "";
}

BOOL CFuncViewPrjDoc::AddFile(int nFileSet, LPCTSTR pszFilePathName, CFile *pMsgFile, CFile *pErrFile)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return FALSE;

	BOOL bFileOpenInProgress = m_bFileOpenInProgress;
	m_bFileOpenInProgress = TRUE;
	BOOL bRetVal = m_arrFileSets[nFileSet].AddFile(pszFilePathName, pMsgFile, pErrFile, FuncDescFileProgressCallback, (LPARAM)this);
	m_bFileOpenInProgress = bFileOpenInProgress;

	return bRetVal;
}

int CFuncViewPrjDoc::FindFile(int nFileSet, LPCTSTR pszFilePathName)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return -1;

	return m_arrFileSets[nFileSet].FindFile(pszFilePathName);
}

BOOL CFuncViewPrjDoc::RemoveFile(int nFileSet, int nIndex)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return FALSE;

	return m_arrFileSets[nFileSet].RemoveFile(nIndex);
}

int CFuncViewPrjDoc::GetFileCount(int nFileSet)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return 0;

	return m_arrFileSets[nFileSet].GetFileCount();
}

CString CFuncViewPrjDoc::GetFilePathName(int nFileSet, int nIndex)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return "";

	return m_arrFileSets[nFileSet].GetFilePathName(nIndex);
}

CString CFuncViewPrjDoc::GetFileName(int nFileSet, int nIndex)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return "";

	return m_arrFileSets[nFileSet].GetFileName(nIndex);
}

CFuncDescFile *CFuncViewPrjDoc::GetFuncDescFile(int nFileSet, int nIndex)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return NULL;

	return m_arrFileSets[nFileSet].GetFuncDescFile(nIndex);
}

int CFuncViewPrjDoc::GetFuncCount(int nFileSet, int nIndex)
{
	if ((nFileSet < 0) || (nFileSet >= GetFileSetCount())) return 0;

	return m_arrFileSets[nFileSet].GetFuncCount(nIndex);
}

BOOL CFuncViewPrjDoc::AllocateMatrixMemory()
{
	FreeMatrixMemory();		// First, make sure old memory has been freed

	int nRows = GetFuncCount(FVFS_LEFT_FILES, -1);
	int nCols = GetFuncCount(FVFS_RIGHT_FILES, -1);
	int i;
	BOOL bFail = FALSE;

	if ((nRows == 0) || (nCols == 0)) return FALSE;

	m_nMatrixRowCount = nRows;
	m_nMatrixColCount = nCols;

	m_ppnMatrix = new double*[nRows];
	if (m_ppnMatrix == NULL) {
		m_nMatrixRowCount = 0;
		m_nMatrixColCount = 0;
		return FALSE;
	}

	for (i=0; i<nRows; i++) {
		m_ppnMatrix[i] = new double[nCols];
		if (m_ppnMatrix[i] == NULL) bFail = TRUE;
	}

	if (bFail) {
		FreeMatrixMemory();
		return FALSE;
	}

	return TRUE;
}

void CFuncViewPrjDoc::FreeMatrixMemory()
{
	if ((m_nMatrixRowCount == 0) ||
		(m_ppnMatrix == NULL)) {
		m_nMatrixRowCount = 0;
		m_nMatrixColCount = 0;
		m_ppnMatrix = NULL;
		return;
	}

	int i;

	for (i=0; i<m_nMatrixRowCount; i++) {
		if (m_ppnMatrix[i] == NULL) continue;
		delete[] (m_ppnMatrix[i]);
	}
	delete[] m_ppnMatrix;

	m_ppnMatrix = NULL;
	m_nMatrixRowCount = 0;
	m_nMatrixColCount = 0;
}

CString CFuncViewPrjDoc::GetMatrixPathName()
{
	return m_strMatrixPathName;
}

void CFuncViewPrjDoc::SetMatrixPathName(LPCTSTR pszPathName, BOOL bFreeCurrentMatrix)
{
	if (bFreeCurrentMatrix) FreeMatrixMemory();

	m_strMatrixPathName = pszPathName;
}

BOOL CFuncViewPrjDoc::ReadOrBuildMatrix(BOOL bForceRebuild)
{
	CStdioFile mtxFile;
	BOOL bHaveFile = FALSE;
	BOOL bFileValid = FALSE;
	CString strTemp;
	CString strTemp2;
	int nPos;
	int nRows;
	int nCols;

	// A call to allocate will clear the old memory,
	//		allocate new, and set the row/col counts:
	if (!AllocateMatrixMemory()) return FALSE;

	if (!m_strMatrixPathName.IsEmpty()) {
		bHaveFile = TRUE;

		// If we aren't forcing a rebuild, see if we can open the file:
		if ((!bForceRebuild) &&
			(mtxFile.Open(m_strMatrixPathName, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText))) {
			strTemp = "";
			if (mtxFile.ReadString(strTemp)) {
				strTemp.TrimLeft();
				strTemp.TrimRight();
				nPos = strTemp.Find(',');
				if (nPos != -1) {
					nRows = atoi(strTemp.Left(nPos));
					nCols = atoi(strTemp.Mid(nPos + 1));
				} else {
					nRows = atoi(strTemp);
					nCols = 0;
				}

				if ((nRows == m_nMatrixRowCount) &&
					(nCols == m_nMatrixColCount)) bFileValid = TRUE;
			}
			if (!bFileValid) mtxFile.Close();
		}
	}

	if ((bHaveFile) && (!bFileValid)) {
		// If we have a filepath but it isn't valid (or we are forcing an overwrite),
		//		try and open the file for writing.  If that fails, assume we
		//		just don't have a file:
		if (!mtxFile.Open(m_strMatrixPathName,
			CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeText))
			bHaveFile = FALSE;
	}

	// At this point, we have one of the following conditions:
	//		bHaveFile	bFileValid		Reasons				Action
	//		---------	----------		------------------	----------------------------------------
	//		FALSE		FALSE			No path specified	Compare putting results only into memory
	//									Failed to create
	//		TRUE		FALSE			File doesn't exist	File has been opened for writing so compare
	//									File's wrong size	to memory and also write to hard file
	//									Forcing Overwrite
	//		FALSE		TRUE			Should never happen	Compare putting results only into memory
	//		TRUE		TRUE			File's correct		File has been opened for reading, read
	//														it into memory rather than doing compare

	CProgressDlg progDlg(IDS_PROGRESS_MATRIX_COMPARE);
	int i, j;
	int nLeftFileIndex;
	int nLeftFuncIndex;
	int nRightFileIndex;
	int nRightFuncIndex;
	CFuncDesc *pLeftFunc;
	CFuncDesc *pRightFunc;

	CWnd *pParent = ((CMDIFrameWnd*)theApp.m_pMainWnd)->GetActiveView();
	if (pParent == NULL) pParent = ((CMDIFrameWnd*)theApp.m_pMainWnd)->GetActiveFrame();

	progDlg.Create(pParent);
	progDlg.SetRange(0, ((bHaveFile && bFileValid) ? m_nMatrixRowCount : m_nMatrixRowCount*m_nMatrixColCount));
	progDlg.SetStep(1);

	if (bHaveFile) {
		if (bFileValid) {
			progDlg.SetStatus("Reading from Matrix File...");

			// If reading from a file and verify x-breakpoints (i.e. righthand function names):
			strTemp = "";
			mtxFile.ReadString(strTemp);
			strTemp.TrimLeft();
			strTemp.TrimRight();
			nPos = strTemp.Find(',');
			strTemp = strTemp.Mid(nPos+1);		// Toss first (unused) field
			strTemp.TrimLeft();
			nRightFileIndex = 0;
			nRightFuncIndex = 0;
			for (j=0; j<m_nMatrixColCount; j++) {
				nPos = strTemp.Find(',');
				if (nPos != -1) {
					strTemp2 = strTemp.Left(nPos);
					strTemp2.TrimRight();
					strTemp = strTemp.Mid(nPos+1);
					strTemp.TrimLeft();
				} else {
					strTemp2 = strTemp;
					strTemp = "";
				}

				pRightFunc = GetNextFunction(FVFS_RIGHT_FILES, nRightFileIndex, nRightFuncIndex);
				if ((pRightFunc == NULL) ||
					(strTemp2.Compare(pRightFunc->GetMainName()) != 0)) {
					// Right-side function names don't match.  Close file to reset things
					//		and call recursively but force the overwrite:
					mtxFile.Close();
					progDlg.DestroyWindow();
					return ReadOrBuildMatrix(TRUE);
				}
			}
		} else {
			progDlg.SetStatus("Comparing and Writing to Matrix File...");

			// If writing to a file, write the size info and x-breakpoints:
			strTemp.Format("%ld,%ld\n", m_nMatrixRowCount, m_nMatrixColCount);
			mtxFile.WriteString(strTemp);
			nRightFileIndex = 0;
			nRightFuncIndex = 0;
			strTemp = "";
			for (j=0; j<m_nMatrixColCount; j++) {
				pRightFunc = GetNextFunction(FVFS_RIGHT_FILES, nRightFileIndex, nRightFuncIndex);
				if (pRightFunc == NULL) continue;
				strTemp += "," + pRightFunc->GetMainName();
			}
			strTemp += "\n";
			mtxFile.WriteString(strTemp);
		}
	} else {
		progDlg.SetStatus("Comparing...");
	}

	nLeftFileIndex = 0;
	nLeftFuncIndex = 0;
	for (i=0; i<m_nMatrixRowCount; i++) {
		pLeftFunc = GetNextFunction(FVFS_LEFT_FILES, nLeftFileIndex, nLeftFuncIndex);
		if (pLeftFunc == NULL) continue;

		if ((bHaveFile) && (bFileValid)) {
			// If reading from a file, do so:
			strTemp = "";
			strTemp2 = "";
			mtxFile.ReadString(strTemp);
			strTemp.TrimLeft();
			strTemp.TrimRight();
			nPos = strTemp.Find(',');
			// Read x-breakpoint
			if (nPos != -1) {
				strTemp2 = strTemp.Left(nPos);
				strTemp2.TrimRight();
			}
			if (strTemp2.Compare(pLeftFunc->GetMainName()) != 0) {
				// Left-side function names don't match.  Close file to reset things
				//		and call recursively but force the overwrite:
				mtxFile.Close();
				progDlg.DestroyWindow();
				return ReadOrBuildMatrix(TRUE);
			}
			strTemp = strTemp.Mid(nPos+1);
			strTemp.TrimLeft();
			for (j=0; j<m_nMatrixColCount; j++) {
				nPos = strTemp.Find(',');
				if (nPos != -1) {
					strTemp2 = strTemp.Left(nPos);
					strTemp2.TrimRight();
					m_ppnMatrix[i][j] = atof(strTemp2);
					strTemp = strTemp.Mid(nPos+1);
					strTemp.TrimLeft();
				} else {
					m_ppnMatrix[i][j] = atof(strTemp);
					strTemp = "";
				}
			}

			progDlg.StepIt();
			if (progDlg.CheckCancelButton()) {
				FreeMatrixMemory();
				return FALSE;
			}
		} else {
			// If not reading from file, we must do full compare
			//		(even if not writing back to a file):
			nRightFileIndex = 0;
			nRightFuncIndex = 0;
			strTemp = pLeftFunc->GetMainName();
			for (j=0; j<m_nMatrixColCount; j++) {
				pRightFunc = GetNextFunction(FVFS_RIGHT_FILES, nRightFileIndex, nRightFuncIndex);
				if (pRightFunc == NULL) continue;

				// Note: Function indexes have already been incremented during GetNextFunction
				m_ppnMatrix[i][j] = ::CompareFunctions(FCM_DYNPROG_GREEDY,
										GetFuncDescFile(FVFS_LEFT_FILES, nLeftFileIndex), nLeftFuncIndex-1,
										GetFuncDescFile(FVFS_RIGHT_FILES, nRightFileIndex), nRightFuncIndex-1,
										FALSE);
				strTemp2.Format(",%.12g", m_ppnMatrix[i][j]);
				strTemp += strTemp2;

				progDlg.StepIt();
				if (progDlg.CheckCancelButton()) {
					FreeMatrixMemory();
					return FALSE;
				}
			}
			strTemp += "\n";
			// If we are writing to a file, do so:
			if ((bHaveFile) && (!bFileValid)) mtxFile.WriteString(strTemp);
		}
	}

	if (bHaveFile) mtxFile.Close();

	return TRUE;
}

BOOL CFuncViewPrjDoc::HaveMatrix()
{
	if ((m_nMatrixRowCount == 0) ||
		(m_nMatrixColCount == 0) ||
		(m_ppnMatrix == NULL)) return FALSE;

	int nRows = GetFuncCount(FVFS_LEFT_FILES, -1);
	int nCols = GetFuncCount(FVFS_RIGHT_FILES, -1);

	if ((nRows != m_nMatrixRowCount) ||
		(nCols != m_nMatrixColCount)) return FALSE;

	return TRUE;
}

CFuncDesc *CFuncViewPrjDoc::GetNextFunction(int nFileSet, int &nFileIndex, int &nFuncIndex)
{
	CFuncDescFile *pFuncFile;
	BOOL bFound;

	if (nFileIndex >= GetFileCount(nFileSet)) return NULL;

	bFound = FALSE;
	for (; (nFileIndex < GetFileCount(nFileSet)); nFileIndex++) {
		pFuncFile = GetFuncDescFile(nFileSet, nFileIndex);
		if (pFuncFile == NULL) {
			nFuncIndex = 0;
			continue;
		}
		if (nFuncIndex < pFuncFile->GetFuncCount()) {
			bFound = TRUE;
			break;
		}
		nFuncIndex = 0;
	}
	if ((!bFound) || (pFuncFile == NULL)) return NULL;

	CFuncDesc *pRetVal = pFuncFile->GetFunc(nFuncIndex);

	nFuncIndex++;

	return pRetVal;
}

CFuncDesc *CFuncViewPrjDoc::GetFileFuncIndexFromLinearIndex(int nFileSet, int nLinearIndex,
															int &nFileIndex, int &nFuncIndex)
{
	CFuncDescFile *pFuncFile;
	BOOL bFound;
	int nLinear;

	nLinear = 0;
	bFound = FALSE;
	for (nFileIndex = 0; nFileIndex < GetFileCount(nFileSet); nFileIndex++) {
		pFuncFile = GetFuncDescFile(nFileSet, nFileIndex);
		if (pFuncFile == NULL) continue;

		for (nFuncIndex = 0; nFuncIndex < pFuncFile->GetFuncCount(); nFuncIndex++) {
			if (nLinear == nLinearIndex) {
				bFound = TRUE;
				break;
			}

			nLinear++;
		}
		if (bFound) break;
	}
	if ((!bFound) || (pFuncFile == NULL)) return NULL;

	return pFuncFile->GetFunc(nFuncIndex);
}


/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc::CFileSet

void CFuncViewPrjDoc::CFileSet::DeleteContents() {
	m_arrFuncDesc.FreeAll();
}

BOOL CFuncViewPrjDoc::CFileSet::AddFile(LPCTSTR pszFilePathName, CFile *pMsgFile, CFile *pErrFile, LPFUNCANALPROGRESSCALLBACK pfnCallback, LPARAM lParamCallback)
{
	CString strFilePathName = pszFilePathName;
	if (strFilePathName.IsEmpty()) return FALSE;

	CFuncDescFile *pFuncDescFile;

	pFuncDescFile = new CFuncDescFile;
	if (pFuncDescFile == NULL) return FALSE;

	pFuncDescFile->SetProgressCallback(pfnCallback, lParamCallback);

	CFile theFile;

	if (!theFile.Open(strFilePathName, CFile::modeRead | CFile::typeBinary | CFile::shareDenyWrite)) {
		delete pFuncDescFile;
		return FALSE;
	}

	if (!pFuncDescFile->ReadFuncDescFile(theFile, pMsgFile, pErrFile)) {
		theFile.Close();
		delete pFuncDescFile;
		return FALSE;
	}

	theFile.Close();

	m_arrFuncDesc.Add(pFuncDescFile);

	return TRUE;
}

int CFuncViewPrjDoc::CFileSet::FindFile(LPCTSTR pszFilePathName)
{
	CString strFilePathName = pszFilePathName;
	int i;
	CFuncDescFile *pFuncDescFile;

	for (i=0; i<m_arrFuncDesc.GetSize(); i++) {
		pFuncDescFile = m_arrFuncDesc.GetAt(i);
		if (pFuncDescFile == NULL) continue;

		if (pFuncDescFile->GetFuncPathName().Compare(strFilePathName) == 0) return i;
	}

	return -1;
}

BOOL CFuncViewPrjDoc::CFileSet::RemoveFile(int nIndex)
{
	ASSERT((nIndex >= 0) && (nIndex < m_arrFuncDesc.GetSize()));

	if ((nIndex < 0) || (nIndex >= m_arrFuncDesc.GetSize())) return FALSE;
	CFuncDescFile *pFuncDesc = m_arrFuncDesc.GetAt(nIndex);

	m_arrFuncDesc.RemoveAt(nIndex);
	if (pFuncDesc) delete pFuncDesc;

	return TRUE;
}

int CFuncViewPrjDoc::CFileSet::GetFileCount()
{
	return m_arrFuncDesc.GetSize();
}

CString CFuncViewPrjDoc::CFileSet::GetFilePathName(int nIndex)
{
	ASSERT((nIndex >= 0) && (nIndex < m_arrFuncDesc.GetSize()));

	if ((nIndex < 0) || (nIndex >= m_arrFuncDesc.GetSize())) return "";
	CFuncDescFile *pFuncDesc = m_arrFuncDesc.GetAt(nIndex);
	if (pFuncDesc == NULL) return "";

	return pFuncDesc->GetFuncPathName();
}

CString CFuncViewPrjDoc::CFileSet::GetFileName(int nIndex)
{
	ASSERT((nIndex >= 0) && (nIndex < m_arrFuncDesc.GetSize()));

	if ((nIndex < 0) || (nIndex >= m_arrFuncDesc.GetSize())) return "";
	CFuncDescFile *pFuncDesc = m_arrFuncDesc.GetAt(nIndex);
	if (pFuncDesc == NULL) return "";

	return pFuncDesc->GetFuncFileName();
}

CFuncDescFile *CFuncViewPrjDoc::CFileSet::GetFuncDescFile(int nIndex)
{
	ASSERT((nIndex >= 0) && (nIndex < m_arrFuncDesc.GetSize()));

	if ((nIndex < 0) || (nIndex >= m_arrFuncDesc.GetSize())) return NULL;
	CFuncDescFile *pFuncDesc = m_arrFuncDesc.GetAt(nIndex);

	return pFuncDesc;
}

int CFuncViewPrjDoc::CFileSet::GetFuncCount(int nIndex)
{
	ASSERT((nIndex >= -1) && (nIndex < m_arrFuncDesc.GetSize()));

	if ((nIndex < -1) || (nIndex >= m_arrFuncDesc.GetSize())) return 0;

	if (nIndex != -1) {
		CFuncDescFile *pFuncDesc = m_arrFuncDesc.GetAt(nIndex);
		if (pFuncDesc == NULL) return 0;
		return pFuncDesc->GetFuncCount();
	}

	return m_arrFuncDesc.GetFuncCount();
}


/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjDoc commands

CFrameWnd *CFuncViewPrjDoc::FindFrame(CRuntimeClass *pFrameClass)
{
	CFrameWnd *pFrame;
	CView *pView;
	POSITION pos;

	pos = GetFirstViewPosition();
	while (pos) {
		pView = GetNextView(pos);
		if (pView == NULL) continue;
		pFrame = pView->GetParentFrame();
		if (pFrame == NULL) continue;
		if (pFrame->IsKindOf(pFrameClass)) return pFrame;
	}

	return NULL;
}

CFrameWnd *CFuncViewPrjDoc::CreateFrame(UINT nIDResource, CRuntimeClass *pFrameClass, BOOL bDoInitialUpdate)
{
	CCreateContext context;
	context.m_pCurrentFrame = NULL;
	context.m_pCurrentDoc = this;
	context.m_pNewViewClass = NULL;
	context.m_pLastView = NULL;
	context.m_pNewDocTemplate = GetDocTemplate();

	CFrameWnd *pFrame = (CFrameWnd*)(pFrameClass->CreateObject());
	if (pFrame == NULL)
	{
		TRACE1("Warning: Dynamic create of frame %hs failed.\n",
			pFrameClass->m_lpszClassName);
		return NULL;
	}
	ASSERT_KINDOF(CFrameWnd, pFrame);

	// create new from resource
	if (!pFrame->LoadFrame(nIDResource,
			WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,   // default frame styles
			NULL, &context))
	{
		TRACE0("Warning: Couldn't create a frame.\n");
		// frame will be deleted in PostNcDestroy cleanup
		return NULL;
	}

	if (bDoInitialUpdate) pFrame->InitialUpdateFrame(this, TRUE);

	return pFrame;
}

void CFuncViewPrjDoc::OnViewFuncDiff() 
{
	CFrameWnd *pFrame;

	pFrame = FindFrame(RUNTIME_CLASS(CChildFrame2));
	if (pFrame) {
//		((CMainFrame*)theApp.m_pMainWnd)->MDIActivate(pFrame);
		ASSERT_KINDOF(CMDIChildWnd, pFrame);
		((CMDIChildWnd*)pFrame)->MDIDestroy();
		return;
	}

	pFrame = CreateFrame(IDR_FUNCDIFFTYPE, RUNTIME_CLASS(CChildFrame2), FALSE);
	if (pFrame == NULL) return;

	CChildFrame2 *pChildFrame = (CChildFrame2 *)pFrame;
	ASSERT(pChildFrame->m_pLeftFuncList != NULL);
	ASSERT(pChildFrame->m_pRightFuncList != NULL);

	if ((pChildFrame->m_pLeftFuncList == NULL) ||
		(pChildFrame->m_pRightFuncList == NULL)) {
		AfxMessageBox("ERROR : Couldn't locate function list views!", MB_OK | MB_ICONEXCLAMATION);
		return;
	}

	pChildFrame->m_pLeftFuncList->SetFileSetIndex(FVFS_LEFT_FILES);
	pChildFrame->m_pRightFuncList->SetFileSetIndex(FVFS_RIGHT_FILES);

	pFrame->InitialUpdateFrame(this, TRUE);
}

void CFuncViewPrjDoc::OnUpdateViewFuncDiff(CCmdUI* pCmdUI)
{
	CFrameWnd *pFrame = FindFrame(RUNTIME_CLASS(CChildFrame2));

	pCmdUI->Enable(!m_bFileOpenInProgress);
	pCmdUI->SetCheck((pFrame != NULL) ? 1 : 0);
}

void CFuncViewPrjDoc::OnViewSymbolMap() 
{
	CFrameWnd *pFrame;

	pFrame = FindFrame(RUNTIME_CLASS(CChildFrame3));
	if (pFrame) {
//		((CMainFrame*)theApp.m_pMainWnd)->MDIActivate(pFrame);
		ASSERT_KINDOF(CMDIChildWnd, pFrame);
		((CMDIChildWnd*)pFrame)->MDIDestroy();
		return;
	}

	pFrame = CreateFrame(IDR_SYMBOLMAPTYPE, RUNTIME_CLASS(CChildFrame3));
	if (pFrame == NULL) return;
}

void CFuncViewPrjDoc::OnUpdateViewSymbolMap(CCmdUI* pCmdUI) 
{
	CFrameWnd *pFrame = FindFrame(RUNTIME_CLASS(CChildFrame3));

	pCmdUI->Enable(!m_bFileOpenInProgress);
	pCmdUI->SetCheck((pFrame != NULL) ? 1 : 0);
}

void CFuncViewPrjDoc::OnViewOutputWindow() 
{
	CFrameWnd *pFrame;

	pFrame = FindFrame(RUNTIME_CLASS(CChildFrame4));
	if (pFrame) {
//		((CMainFrame*)theApp.m_pMainWnd)->MDIActivate(pFrame);
		ASSERT_KINDOF(CMDIChildWnd, pFrame);
		((CMDIChildWnd*)pFrame)->MDIDestroy();
		return;
	}

	pFrame = CreateFrame(IDR_OUTPUTTYPE, RUNTIME_CLASS(CChildFrame4));
	if (pFrame == NULL) return;
}

void CFuncViewPrjDoc::OnUpdateViewOutputWindow(CCmdUI* pCmdUI) 
{
	CFrameWnd *pFrame = FindFrame(RUNTIME_CLASS(CChildFrame4));

	pCmdUI->Enable(!m_bFileOpenInProgress);
	pCmdUI->SetCheck((pFrame != NULL) ? 1 : 0);
}

void CFuncViewPrjDoc::OnViewCompMatrix() 
{
	CFrameWnd *pFrame;

	pFrame = FindFrame(RUNTIME_CLASS(CChildFrame5));
	if (pFrame) {
//		((CMainFrame*)theApp.m_pMainWnd)->MDIActivate(pFrame);
		ASSERT_KINDOF(CMDIChildWnd, pFrame);
		((CMDIChildWnd*)pFrame)->MDIDestroy();
		return;
	}

	pFrame = CreateFrame(IDR_COMPMATRIXTYPE, RUNTIME_CLASS(CChildFrame5));
	if (pFrame == NULL) return;
}

void CFuncViewPrjDoc::OnUpdateViewCompMatrix(CCmdUI* pCmdUI) 
{
	CFrameWnd *pFrame = FindFrame(RUNTIME_CLASS(CChildFrame5));

	pCmdUI->Enable(!m_bFileOpenInProgress);
	pCmdUI->SetCheck((pFrame != NULL) ? 1 : 0);
}

void CFuncViewPrjDoc::OnViewCompDiff() 
{
	CFrameWnd *pFrame;

	pFrame = FindFrame(RUNTIME_CLASS(CChildFrame6));
	if (pFrame) {
//		((CMainFrame*)theApp.m_pMainWnd)->MDIActivate(pFrame);
		ASSERT_KINDOF(CMDIChildWnd, pFrame);
		((CMDIChildWnd*)pFrame)->MDIDestroy();
		return;
	}

	pFrame = CreateFrame(IDR_COMPDIFFEDITTYPE, RUNTIME_CLASS(CChildFrame6));
	if (pFrame == NULL) return;
}

void CFuncViewPrjDoc::OnUpdateViewCompDiff(CCmdUI* pCmdUI) 
{
	CFrameWnd *pFrame = FindFrame(RUNTIME_CLASS(CChildFrame6));

	pCmdUI->Enable(!m_bFileOpenInProgress);
	pCmdUI->SetCheck((pFrame != NULL) ? 1 : 0);
}

void CFuncViewPrjDoc::UpdateFrameCounts()
{
	CMap<CString, LPCSTR, int, int> nFrames;
	CMap<CString, LPCSTR, int, int> iFrame;
	int nTemp;

	// walk all frames of views (mark and sweep approach)
	POSITION pos = GetFirstViewPosition();
	while (pos != NULL)
	{
		CView* pView = GetNextView(pos);
		ASSERT_VALID(pView);
		ASSERT(::IsWindow(pView->m_hWnd));
		if (pView->IsWindowVisible())   // Do not count invisible windows.
		{
			CFrameWnd* pFrame = pView->GetParentFrame();
			if (pFrame != NULL)
				pFrame->m_nWindow = -1;     // unknown

			nFrames.SetAt(pFrame->GetRuntimeClass()->m_lpszClassName, 0);
			iFrame.SetAt(pFrame->GetRuntimeClass()->m_lpszClassName, 1);
		}
	}

	// now do it again counting the unique ones
	pos = GetFirstViewPosition();
	while (pos != NULL)
	{
		CView* pView = GetNextView(pos);
		ASSERT_VALID(pView);
		ASSERT(::IsWindow(pView->m_hWnd));
		if (pView->IsWindowVisible())   // Do not count invisible windows.
		{
			CFrameWnd* pFrame = pView->GetParentFrame();
			if (pFrame != NULL && pFrame->m_nWindow == -1)
			{
				ASSERT_VALID(pFrame);
				// not yet counted (give it a 1 based number)
				nFrames.Lookup(pFrame->GetRuntimeClass()->m_lpszClassName, nTemp);
				pFrame->m_nWindow = ++nTemp;
				nFrames.SetAt(pFrame->GetRuntimeClass()->m_lpszClassName, nTemp);
			}
		}
	}

	// lastly walk the frames and update titles (assume same order)
	// go through frames updating the appropriate one
	pos = GetFirstViewPosition();
	while (pos != NULL)
	{
		CView* pView = GetNextView(pos);
		ASSERT_VALID(pView);
		ASSERT(::IsWindow(pView->m_hWnd));
		if (pView->IsWindowVisible())   // Do not count invisible windows.
		{
			CFrameWnd* pFrame = pView->GetParentFrame();
			if (pFrame != NULL)
			{
				iFrame.Lookup(pFrame->GetRuntimeClass()->m_lpszClassName, nTemp);
				if (pFrame->m_nWindow == nTemp)
				{
					ASSERT_VALID(pFrame);
					nFrames.Lookup(pFrame->GetRuntimeClass()->m_lpszClassName, nTemp);
					if (nTemp == 1)
						pFrame->m_nWindow = 0;      // the only one of its kind
					pFrame->OnUpdateFrameTitle(TRUE);
					iFrame.Lookup(pFrame->GetRuntimeClass()->m_lpszClassName, nTemp);
					iFrame.SetAt(pFrame->GetRuntimeClass()->m_lpszClassName, nTemp + 1);
				}
			}
		}
	}
}

void CFuncViewPrjDoc::OnSymbolsReset() 
{
	if (AfxMessageBox("Are you sure you want to reset all symbols?", MB_YESNO | MB_ICONQUESTION) != IDYES) return;

	m_objSymbolMap.FreeAll();
	m_mapLeftToRightFunc.RemoveAll();
	m_mapRightToLeftFunc.RemoveAll();

	m_strCompDiffText = "";

	UpdateAllViews(NULL, SYMBOL_MAP_ALL, NULL);			// Signal all symbol table 
	UpdateAllViews(NULL, COMP_DIFF_TYPE_BASE, NULL);	// Update CompDiffEditViews
}

void CFuncViewPrjDoc::OnSymbolsExport() 
{
	static const char pszFilter[] = "Symbol Files (*.sym)|*.sym|All Files (*.*)|*.*||";

	CFileDialog dlg(FALSE, "sym", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST,
						pszFilter, NULL);

	if (dlg.DoModal() != IDOK) return;

	CStdioFile outFile;

	if (!outFile.Open(dlg.GetPathName(), CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite | CFile::typeText)) {
		AfxMessageBox("Failed to create export file!", MB_OK | MB_ICONEXCLAMATION);
		return;
	}

	CStringArray arrSym;
	CStringArray arrSymMatch;
	CDWordArray arrHitCount;
	DWORD nTotalHitCount;
	int i,j,k;
	CString strTemp;

	CWaitCursor wait;

	for (i=0; i<4; i++) {
		switch (i) {
			case 0:
				m_objSymbolMap.GetLeftSideCodeSymbolList(arrSym);
				outFile.WriteString("Left-Side Code Symbols:\n");
				break;

			case 1:
				m_objSymbolMap.GetLeftSideDataSymbolList(arrSym);
				outFile.WriteString("\nLeft-Side Data Symbols:\n");
				break;

			case 2:
				m_objSymbolMap.GetRightSideCodeSymbolList(arrSym);
				outFile.WriteString("\n\nRight-Side Code Symbols:\n");
				break;

			case 3:
				m_objSymbolMap.GetRightSideDataSymbolList(arrSym);
				outFile.WriteString("\nRight-Side Data Symbols:\n");
				break;

			default:
				continue;
		}

		for (j=0; j<arrSym.GetSize(); j++) {
			switch (i) {
				case 0:
					nTotalHitCount = m_objSymbolMap.GetLeftSideCodeHitList(arrSym.GetAt(j), arrSymMatch, arrHitCount);
					break;

				case 1:
					nTotalHitCount = m_objSymbolMap.GetLeftSideDataHitList(arrSym.GetAt(j), arrSymMatch, arrHitCount);
					break;

				case 2:
					nTotalHitCount = m_objSymbolMap.GetRightSideCodeHitList(arrSym.GetAt(j), arrSymMatch, arrHitCount);
					break;

				case 3:
					nTotalHitCount = m_objSymbolMap.GetRightSideDataHitList(arrSym.GetAt(j), arrSymMatch, arrHitCount);
					break;

				default:
					continue;
			}

			outFile.WriteString(arrSym.GetAt(j));

			ASSERT(arrSymMatch.GetSize() == arrHitCount.GetSize());		// These should have same number of members!

			for (k=0; k<arrSymMatch.GetSize(); k++) {
				ASSERT(nTotalHitCount != 0);							// Should never have members with no hits!
				strTemp.Format(",%s,%ld,%f%%", LPCTSTR(arrSymMatch.GetAt(k)), arrHitCount.GetAt(k),
												((double)arrHitCount.GetAt(k)/nTotalHitCount)*100);
				outFile.WriteString(strTemp);
			}
			outFile.WriteString("\n");
		}
	}

	outFile.Close();
}

void CFuncViewPrjDoc::OnUpdateSymbolsExport(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!m_objSymbolMap.IsEmpty());
}

void CFuncViewPrjDoc::OnMatrixRebuild() 
{
	if (!ReadOrBuildMatrix(FALSE)) {
		AfxMessageBox("Comparison Matrix Build Failed!", MB_OK | MB_ICONEXCLAMATION);
	}

	UpdateAllViews(NULL, MATRIX_TYPE_BASE, NULL);
}

void CFuncViewPrjDoc::OnMatrixRebuildForce() 
{
	if (!ReadOrBuildMatrix(TRUE)) {
		AfxMessageBox("Comparison Matrix Build Failed!", MB_OK | MB_ICONEXCLAMATION);
	}

	UpdateAllViews(NULL, MATRIX_TYPE_BASE, NULL);
}

void CFuncViewPrjDoc::AddFunctionAssociation(LPCTSTR pszLeftFuncName, LPCTSTR pszRightFuncName)
{
	m_mapLeftToRightFunc.SetAt(pszLeftFuncName, pszRightFuncName);
	m_mapRightToLeftFunc.SetAt(pszRightFuncName, pszLeftFuncName);
}

BOOL CFuncViewPrjDoc::LookupLeftFuncAssociation(LPCTSTR pszLeftFuncName, CString &strRightFuncName)
{
	return m_mapLeftToRightFunc.Lookup(pszLeftFuncName, strRightFuncName);
}

BOOL CFuncViewPrjDoc::LookupRightFuncAssociation(LPCTSTR pszRightFuncName, CString &strLeftFuncName)
{
	return m_mapRightToLeftFunc.Lookup(pszRightFuncName, strLeftFuncName);
}

<file_sep>/programs/m6811dis/dfc.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      DFC   -- DataFileConverter Class

      This is the C++ DataFileConverter Object Class Header File.

	  Author:  <NAME>
      Date:    January 29, 1997

      Written in: Borland C++ 4.52

      Updated: June 22, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

*/

#ifndef DFC_H
#define DFC_H

#include <iostream>
#include <vector>
#include "memclass.h"
#include "errmsgs.h"

#define DFC_FILL_BYTE(abyte) (abyte * 256)

enum {   DFC_NO_FILL,
			DFC_ALWAYS_FILL_WITH,
			DFC_ALWAYS_FILL_WITH_RANDOM,
			DFC_CONDITIONAL_FILL_WITH,
			DFC_CONDITIONAL_FILL_WITH_RANDOM };

#define DFC_FILL_TYPE(atype) ((unsigned char) DFC_##atype)
#define GET_DFC_FILL_TYPE(afill) ((unsigned char)(afill%256))
#define GET_DFC_FILL_BYTE(afill) ((unsigned char)(afill/256))

#define NO_FILL \
	(DFC_FILL_TYPE(NO_FILL))
#define ALWAYS_FILL_WITH(abyte) \
	(DFC_FILL_TYPE(ALWAYS_FILL_WITH) | DFC_FILL_BYTE(abyte))
#define ALWAYS_FILL_WITH_RANDOM \
	(DFC_FILL_TYPE(ALWAYS_FILL_WITH_RANDOM))
#define CONDITIONAL_FILL_WITH(abyte) \
	(DFC_FILL_TYPE(CONDITIONAL_FILL_WITH) | DFC_FILL_BYTE(abyte))
#define CONDITIONAL_FILL_WITH_RANDOM \
   (DFC_FILL_TYPE(CONDITIONAL_FILL_WITH_RANDOM))

/////////////////////////////////////////////////////////////////////////////


class CDFCObject
{
public:
	// Construction
	CDFCObject();
	virtual ~CDFCObject();

	// GetLibraryName: Returns the basic name of the DFC Library, like "Intel", "Binary", etc.
	virtual std::string GetLibraryName(void) const = 0;

	// GetShortDescription: Returns the short description of the DFC Library, like "Intel Hex Data File Converter":
	virtual std::string GetShortDescription(void) const = 0;

	// GetDescription: Returns a long description of the DFC Library, with more details than short description:
	virtual std::string GetDescription(void) const = 0;

		// DefaultExtension:
		//    This function returns a constant character string that represents
		//    the default filename extension for the defined data file type.  This
		//    is used by calling programs in open-file dialogs.
	virtual const char *DefaultExtension(void) const { return "*"; }


	// RetrieveFileMapping
	//    This is a null function that must be overriden in child Data File Converter
	//    classes.  Overriding functions are to read the open BINARY file specified
	//    by 'aFile' and determine the mapping (or range) criteria for the particular
	//    file that is necessary to completely read the file, but including all
	//    breaks that exist in the file.  For example, a binary file will set only
	//    the base range mapping and set it to the NewBase with the size equal to the
	//    file length, since the entire file is read at that base.  An Intel hex file,
	//    for example, will be searched for each skip in offset and that will start
	//    new range entries.  So if an Intel file, for example, has a group at 0000-7FFF,
	//    a group from C000-DFFF and a group from FFD6-FFFF and the NewBase is 10000,
	//    then 3 range entries will be created as: 1) Start: 10000, Size: 8000,
	//    2) Start 1C000, Size: 2000, and 3) Start: 1FFD6, Size: 2A.
	//    Such a routine is needed when reading an unknown file in, as in a generic
	//    file converter routine.  By reading the necessary sizing structure of the
	//    data file, memory can dynamically be allocated to accommodate such a file.
	//    This function returns a '1' if everything was read without problems.  A
	//    '0' is returned if a problem was found in determining the range (but a
	//    problem that is non-detrimental).
	//    The following throw backs are performed AND loading is halted as follows:
	//       ERR_CHECKSUM if there is a checksum error encountered during loading.
	//       ERR_UNEXPECTED_EOF if end_of_file is encountered before it was expected.
	//       ERR_OUT_OF_MEMORY if an allocation of a new MemRange entry fails.
	//
	virtual int RetrieveFileMapping(std::istream *aFile, unsigned long NewBase, TMemRange *aRange) const;

	// ReadDataFile:
	//    This is a null function that must be overriden in child Data File Converter
	//    routines.  Overriding functions are to read the open BINARY file specified
	//    by 'aFile' into the Memory Class object 'aMemory' with an offset of
	//    'NewBase'.  Files that have addresses specified internally, the internal
	//    addresses are treaded as 'Logical Addresses' in the memory structure.
	//    NewBase too is treaded as a Logical Address, but this can be used to
	//    load a file that really has physical addresses into a special logical
	//    area.    For example, a file with internal address for 0x0000-0x7FFF
	//    that needs to be read into logical 0x10000.  Just use NewBase=0x10000.
	//    The Memory locations that receive bytes from the loaded file will have
	//    their Descriptor bytes changed to 'aDesc'.  This function returns a
	//    '1' if everything was read without problems.  A '0' is returned if
	//    a memory location overwrote an existing already loaded location.
	//    The following throw backs are performed AND loading is halted as follows:
	//       ERR_CHECKSUM if there is a checksum error encountered during loading.
	//       ERR_UNEXPECTED_EOF if end_of_file is encountered before it was expected.
	//       ERR_OVERFLOW if an attempt is made to load an address outside the memory bounds.
	//
	virtual int ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory,
													unsigned char aDesc) const = 0;

	// WriteDataFile:
	//    This is a null function that must be overriden in child Data File Converter
	//    routines.  Overriding functions are to write the open BINARY file specified
	//    by 'aFile' from the Memory Class object 'aMemory' from the LOGICAL memory
	//    range specified by 'aRange'.  If 'UsePhysicalAddr' is non-zero, calls are
	//    made to the Memory object to convert the logical addresses to physical
	//    addresses, and the physical addresses are used in the output file.  The
	//    offset 'NewBase' is added to the final address going in the file.  Note
	//    that this doesn't apply to children writing an image file that has no
	//    address information (like a binary file).  Data written is based on the
	//    validator 'aDesc'.  If 'aDesc' is ZERO, ALL data in the specified range
	//    is written.  Otherwise, the 'aDesc' is ANDED with EACH descriptor byte from
	//    memory and if the result is non-zero, the data is written.  This allows
	//    code to be written separately from data, etc...
	//    The the validator computes as False, then data is actually written or
	//    not written based on the FillMode value, as follows:
	//          0000 = No filling done on unused bytes -- on Hex files, this
	//                   results in a smaller, more compact file.
	//          xx01 = Fill unused bytes with the byte value specified by 'xx'.
	//                   This is useful for binary files.  (Regardless of type)
	//          0002 = Fill unused bytes with random values.  This is useful for
	//                   data fodder.
	//          xx03 = Fill unused bytes with the byte values specified by 'xx'
	//                   if and only if datafile type requires padding (such as binary).
	//          0004 = Fill unused bytes with random values if and only
	//                   if datafile type requires padding (such as binary).  This
	//                   is useful for data fodder.
	//
	//       Note types 3&4 are equivalent to 1&2 except that the particular DFC
	//          makes the decision as to whether padding is necessary or not.  This
	//          allows the calling program to be totally generic in the call,
	//          without having to know (for example) if a file is a binary type
	//          and needs padding or a hex type and doesn't.  Hex file types should
	//          not pad on such instances, but binary file types should but only
	//          within the specified range.
	//
	//    A '1' is returned if everything was successful in the write operation.
	//    The following throw backs are performed AND writing is halted as follows:
	//       ERR_WRITEFAILED if there was an error in while writing to the output file.
	//       ERR_OVERFLOW if a write to a address included file yielded an oversized address.
	virtual int WriteDataFile(std::ostream *aFile, TMemRange *aRange, unsigned long NewBase, TMemObject *aMemory,
													unsigned char aDesc, int UsePhysicalAddr,
													unsigned int FillMode) const = 0;
};


/////////////////////////////////////////////////////////////////////////////

class CDFCArray : public std::vector<CDFCObject *>
{
private:
	CDFCArray();
public:
	~CDFCArray();

	const CDFCObject *locateDFC(const std::string &strLibraryName) const;
	static CDFCArray *instance();
};

/////////////////////////////////////////////////////////////////////////////

#endif	// DFC_H

<file_sep>/programs/funcanal/FuncView/FuncViewPrjVw.h
// FuncViewPrjVw.h : interface of the CFuncViewPrjView class
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncViewPrjVw.h,v $
// Revision 1.1  2003/09/13 05:45:45  dewhisna
// Initial Revision
//
//

#if !defined(AFX_FUNCVIEWPRJVW_H__D64C9E65_798E_486F_8563_28B4FD7D6EDD__INCLUDED_)
#define AFX_FUNCVIEWPRJVW_H__D64C9E65_798E_486F_8563_28B4FD7D6EDD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CFuncViewPrjDoc;

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjView view

class CFuncViewPrjView : public CTreeView
{
protected: // create from serialization only
	CFuncViewPrjView();
	DECLARE_DYNCREATE(CFuncViewPrjView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();

protected:
	HTREEITEM m_hMatrixBaseNode;

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CFuncViewPrjView)
	public:
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
	protected:
	virtual void OnInitialUpdate(); // called first time after construct
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CFuncViewPrjView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:
	void FillFileLists();
	void FillMatrixLists();

// Generated message map functions
protected:
	//{{AFX_MSG(CFuncViewPrjView)
	afx_msg void OnEditClear();
	afx_msg void OnUpdateEditClear(CCmdUI* pCmdUI);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in FuncViewPrjVw.cpp
inline CFuncViewPrjDoc* CFuncViewPrjView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_FUNCVIEWPRJVW_H__D64C9E65_798E_486F_8563_28B4FD7D6EDD__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by FuncView.rc
//
#define IDD_ABOUTBOX                    100
#define CG_IDD_PROGRESS                 101
#define CG_IDS_PROGRESS_CAPTION         102
#define IDS_PROGRESS_MATRIX_COMPARE     103
#define IDR_MAINFRAME                   128
#define IDR_FUNCVPTYPE                  129
#define IDR_FUNCDIFFTYPE                130
#define IDR_SYMBOLMAPTYPE               131
#define IDR_OUTPUTTYPE                  132
#define IDR_COMPMATRIXTYPE              133
#define IDR_COMPDIFFEDITTYPE            134
#define CG_IDC_PROGDLG_PROGRESS         1001
#define CG_IDC_PROGDLG_PERCENT          1002
#define CG_IDC_PROGDLG_STATUS           1003
#define ID_VIEW_FUNC_DIFF               32771
#define ID_INDICATOR_MATCH_PERCENT      32772
#define ID_SYMBOLS_ADD                  32773
#define ID_SYMBOLS_RESET                32774
#define ID_SYMBOLS_EXPORT               32775
#define ID_VIEW_SYMBOL_MAP              32776
#define ID_VIEW_OUTPUT_WINDOW           32777
#define ID_VIEW_COMP_MATRIX             32778
#define ID_MATRIX_REBUILD               32779
#define ID_MATRIX_REBUILD_FORCE         32780
#define ID_VIEW_COMP_DIFF               32781

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS                     1
#define _APS_NEXT_RESOURCE_VALUE        134
#define _APS_NEXT_COMMAND_VALUE         32782
#define _APS_NEXT_CONTROL_VALUE         1004
#define _APS_NEXT_SYMED_VALUE           104
#endif
#endif
<file_sep>/programs/funcanal/FuncView/FuncView.h
// FuncView.h : main header file for the FUNCVIEW application
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncView.h,v $
// Revision 1.1  2003/09/13 05:45:42  dewhisna
// Initial Revision
//
//

#if !defined(AFX_FUNCVIEW_H__B8D0CB16_BC1E_4ED0_856D_C48685662F00__INCLUDED_)
#define AFX_FUNCVIEW_H__B8D0CB16_BC1E_4ED0_856D_C48685662F00__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef __AFXWIN_H__
	#error include 'stdafx.h' before including this file for PCH
#endif

#include "resource.h"       // main symbols

/////////////////////////////////////////////////////////////////////////////
// CFuncViewApp:
// See FuncView.cpp for the implementation of this class
//

class CFuncViewApp : public CWinApp
{
public:
	CFuncViewApp();

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CFuncViewApp)
	public:
	virtual BOOL InitInstance();
	//}}AFX_VIRTUAL

// Implementation
	//{{AFX_MSG(CFuncViewApp)
	afx_msg void OnAppAbout();
		// NOTE - the ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

extern CFuncViewApp theApp;

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_FUNCVIEW_H__B8D0CB16_BC1E_4ED0_856D_C48685662F00__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/FuncDiffEditView.cpp
// FuncDiffEditView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncDiffEditView.cpp,v $
// Revision 1.1  2003/09/13 05:45:39  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "FuncViewPrjDoc.h"
#include "FuncDiffEditView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFuncDiffEditView

IMPLEMENT_DYNCREATE(CFuncDiffEditView, CEditView)

CFuncDiffEditView::CFuncDiffEditView()
{
	m_fntEditor.CreatePointFont(100, "Courier New");
	m_strMatchPercentage = "";
}

CFuncDiffEditView::~CFuncDiffEditView()
{
}


BEGIN_MESSAGE_MAP(CFuncDiffEditView, CEditView)
	//{{AFX_MSG_MAP(CFuncDiffEditView)
	ON_COMMAND(ID_SYMBOLS_ADD, OnSymbolsAdd)
	ON_UPDATE_COMMAND_UI(ID_SYMBOLS_ADD, OnUpdateSymbolsAdd)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CFuncDiffEditView diagnostics

#ifdef _DEBUG
void CFuncDiffEditView::AssertValid() const
{
	CEditView::AssertValid();
}

void CFuncDiffEditView::Dump(CDumpContext& dc) const
{
	CEditView::Dump(dc);
}

CFuncViewPrjDoc* CFuncDiffEditView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CFuncDiffEditView message handlers

void CFuncDiffEditView::OnInitialUpdate() 
{
	CEdit &theEdit = GetEditCtrl();

	theEdit.SetFont(&m_fntEditor);
	theEdit.SetReadOnly(TRUE);

	CEditView::OnInitialUpdate();	// This calls OnUpdate
}

void CFuncDiffEditView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

//	CEdit &theEdit = GetEditCtrl();
//	theEdit.SetWindowText("");

	switch (lHint) {
		case 0:						// Normal Update
			m_LeftFunc.Reset();
			m_RightFunc.Reset();
			break;

		case FILESET_TYPE_BASE:		// Left function changed
			m_LeftFunc = *((CFuncViewFuncRef *)pHint);
			break;

		case FILESET_TYPE_BASE+1:	// Right function changed
			m_RightFunc = *((CFuncViewFuncRef *)pHint);
			break;
	}

	if ((lHint == 0) || ((lHint >= FILESET_TYPE_BASE) && (lHint <= FILESET_TYPE_LAST))) {
		DoDiff();
	}
}

void CFuncDiffEditView::DoDiff()
{
	CEdit &theEdit = GetEditCtrl();

	if ((m_LeftFunc.m_pFile == NULL) ||
		(m_RightFunc.m_pFile == NULL) ||
		(m_LeftFunc.m_nIndex < 0) ||
		(m_RightFunc.m_nIndex < 0)) {
		m_strMatchPercentage = "";
		theEdit.SetWindowText("");
		return;
	}

//	double nCompResult = ::CompareFunctions(FCM_DYNPROG_GREEDY,
//								m_pLeftFunc->m_pFile, m_pLeftFunc->m_nIndex,
//								m_pRightFunc->m_pFile, m_pRightFunc->m_nIndex, TRUE);

	CWaitCursor wait;
	double nCompResult;

	CString strTemp = ::DiffFunctions(FCM_DYNPROG_GREEDY,
								m_LeftFunc.m_pFile, m_LeftFunc.m_nIndex,
								m_RightFunc.m_pFile, m_RightFunc.m_nIndex, OO_NONE, nCompResult);

	m_strMatchPercentage.Format("Match: %f%%", nCompResult*100);

	// Convert LF's to CRLF's so editor will display them correctly:
	CString strTemp2 = "";
	int pos;

	while (!strTemp.IsEmpty()) {
		pos = strTemp.Find('\n');
		if (pos != -1) {
			strTemp2 += strTemp.Left(pos);
			strTemp2 += "\r\n";
			strTemp = strTemp.Mid(pos+1);
		} else {
			strTemp2 += strTemp;
			strTemp = "";
		}
	}

	theEdit.SetWindowText(strTemp2);
}

void CFuncDiffEditView::OnSymbolsAdd() 
{
	if ((m_LeftFunc.m_pFile == NULL) ||
		(m_RightFunc.m_pFile == NULL) ||
		(m_LeftFunc.m_nIndex < 0) ||
		(m_RightFunc.m_nIndex < 0)) {
		return;
	}

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	CWaitCursor wait;
	double nCompResult;
	CSymbolMap &theSymbolMap = pDoc->GetSymbolMap();
	CString strTemp;

	CFuncDesc *pLeftFunc = m_LeftFunc.m_pFile->GetFunc(m_LeftFunc.m_nIndex);
	CFuncDesc *pRightFunc = m_RightFunc.m_pFile->GetFunc(m_RightFunc.m_nIndex);

	if ((pLeftFunc != NULL) && (pRightFunc != NULL)) {
		if (pDoc->LookupLeftFuncAssociation(pLeftFunc->GetMainName(), strTemp)) return;
		if (pDoc->LookupRightFuncAssociation(pRightFunc->GetMainName(), strTemp)) return;

		if (!pDoc->GetCompDiffText().IsEmpty()) pDoc->GetCompDiffText() += "\n";
		pDoc->GetCompDiffText() += ::DiffFunctions(FCM_DYNPROG_GREEDY,
						m_LeftFunc.m_pFile, m_LeftFunc.m_nIndex,
						m_RightFunc.m_pFile, m_RightFunc.m_nIndex, OO_ADD_ADDRESS, nCompResult, &theSymbolMap);

		pDoc->AddFunctionAssociation(pLeftFunc->GetMainName(), pRightFunc->GetMainName());
	}

	pDoc->UpdateAllViews(this, SYMBOL_MAP_ALL, NULL);
	pDoc->UpdateAllViews(this, COMP_DIFF_TYPE_BASE, NULL);	// Update CompDiffEditViews
}

void CFuncDiffEditView::OnUpdateSymbolsAdd(CCmdUI* pCmdUI) 
{
	if ((m_LeftFunc.m_pFile == NULL) ||
		(m_RightFunc.m_pFile == NULL) ||
		(m_LeftFunc.m_nIndex < 0) ||
		(m_RightFunc.m_nIndex < 0)) {
		pCmdUI->Enable(FALSE);
		return;
	}

	pCmdUI->Enable(TRUE);
}

<file_sep>/programs/funcanal/funccomp.h
// funccomp.h: interface for the Fuzzy Function Comparison Logic
//
// $Log: funccomp.h,v $
// Revision 1.2  2003/09/13 05:39:49  dewhisna
// Added output options and returning of match percentage to function diff.
//
// Revision 1.1  2003/02/09 06:59:30  dewhisna
// Initial Revision - Split comparison logic from Function File I/O
//
//

#ifndef _FUNCCOMP_H_
#define _FUNCCOMP_H_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


class CFuncDescFile;
class CSymbolMap;

enum FUNC_COMPARE_METHOD {
		FCM_DYNPROG_XDROP = 0,
		FCM_DYNPROG_GREEDY = 1
};

// Output Options:
//		These are OR'd bit fields of output-options used
//		in diff and CreateOutputLine methods
#define OO_NONE 0
#define OO_ADD_ADDRESS 1

double CompareFunctions(FUNC_COMPARE_METHOD nMethod,
						CFuncDescFile *pFile1, int nFile1FuncNdx,
						CFuncDescFile *pFile2, int nFile2FuncNdx,
						BOOL bBuildEditScript);
BOOL GetLastEditScript(CStringArray &anArray);
CString DiffFunctions(FUNC_COMPARE_METHOD nMethod,
						CFuncDescFile *pFile1, int nFile1FuncNdx,
						CFuncDescFile *pFile2, int nFile2FuncNdx,
						DWORD nOutputOptions,
						double &nMatchPercent,
						CSymbolMap *pSymbolMap = NULL);

#endif	// _FUNCCOMP_H_

<file_sep>/programs/m6811dis/m6811gdc.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

//
//	M6811GDC -- This is the class definition for the M6811 Disassembler GDC module
//

#ifndef _M6811GDC_H
#define _M6811GDC_H

#include "gdc.h"

#define OCTL_MASK 0xFF			// Mask for our control byte
#define MAKEOCTL(d, s) (((d & 0x0F) << 4) | (s & 0x0F))
#define OCTL_SRC (m_CurrentOpcode.m_Control & 0x0F)
#define OCTL_DST ((m_CurrentOpcode.m_Control >> 4) & 0x0F)

#define OGRP_MASK 0xFF			// Mask for our group byte
#define MAKEOGRP(d, s) (((d & 0x0F) << 4) | (s & 0x0F))
#define OGRP_SRC (m_CurrentOpcode.m_Group & 0x0F)
#define OGRP_DST ((m_CurrentOpcode.m_Group >> 4) & 0x0F)

class CM6811Disassembler : public CDisassembler
{
public:
	CM6811Disassembler();

	virtual unsigned int GetVersionNumber(void);
	virtual std::string GetGDCLongName(void);
	virtual std::string GetGDCShortName(void);

	virtual bool ResolveIndirect(unsigned int nAddress, unsigned int& nResAddress, int nType);
	virtual std::string GetExcludedPrintChars(void);
	virtual std::string GetHexDelim(void);
	virtual std::string GetCommentStartDelim(void);
	virtual std::string	GetCommentEndDelim(void);
	virtual bool CompleteObjRead(bool bAddLabels = true, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);
	virtual bool RetrieveIndirect(std::ostream *msgFile = NULL, std::ostream *errFile = NULL);

	virtual std::string FormatLabel(LABEL_CODE nLC, const std::string & szLabel, unsigned int nAddress);
	virtual std::string FormatMnemonic(MNEMONIC_CODE nMCCode);
	virtual std::string FormatOperands(MNEMONIC_CODE nMCCode);
	virtual std::string FormatComments(MNEMONIC_CODE nMCCode);

	virtual bool WritePreSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);

private:
	bool MoveOpcodeArgs(unsigned int nGroup);
	bool DecodeOpcode(unsigned int nGroup, unsigned int nControl, bool bAddLabels, std::ostream *msgFile, std::ostream *errFile);
	void CreateOperand(unsigned int nGroup, std::string& sOpStr);
	bool CheckBranchOutside(unsigned int nGroup);
	std::string LabelDeref2(unsigned int nAddress);
	std::string LabelDeref4(unsigned int nAddress);

	unsigned int OpPointer;
	unsigned int StartPC;

	int SectionCount;

	bool CBDef;
};


#endif	// _M6811GDC_H
<file_sep>/programs/funcanal/FuncView/FuncListView.cpp
// FuncListView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncListView.cpp,v $
// Revision 1.1  2003/09/13 05:45:40  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "FuncViewPrjDoc.h"
#include "FuncListView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFuncListView

IMPLEMENT_DYNCREATE(CFuncListView, CListView)

CFuncListView::CFuncListView()
{
	m_nFileSet = -1;
}

CFuncListView::~CFuncListView()
{
}


BEGIN_MESSAGE_MAP(CFuncListView, CListView)
	//{{AFX_MSG_MAP(CFuncListView)
	ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnItemchanged)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CFuncListView diagnostics

#ifdef _DEBUG
void CFuncListView::AssertValid() const
{
	CListView::AssertValid();
}

void CFuncListView::Dump(CDumpContext& dc) const
{
	CListView::Dump(dc);
}

CFuncViewPrjDoc* CFuncListView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CFuncListView message handlers

void CFuncListView::OnInitialUpdate() 
{
	CListCtrl &theList = GetListCtrl();

	theList.ModifyStyle(0, LVS_NOSORTHEADER | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS, SWP_NOACTIVATE);
	theList.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

	theList.InsertColumn(0, "Function Name", LVCFMT_LEFT, 100, 0);
	theList.InsertColumn(1, "Absolute Addr", LVCFMT_RIGHT, 100, 1);

	// Call the base OnInitialUpdate which will call OnUpdate which will call FillFuncList:
	CListView::OnInitialUpdate();
}

void CFuncListView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

	switch (lHint) {
		case 0:						// Normal update
			FillFuncList();
			break;
	}

	if ((lHint >= FILESET_TYPE_BASE) && (lHint <= FILESET_TYPE_LAST)) {
		// FILESET_TYPE_BASE+nFileSet = Document Fileset Function update (pHint = &CFuncViewFuncRef)
	}


	if ((lHint >= SYMBOL_MAP_TYPE_BASE) && (lHint <= SYMBOL_MAP_TYPE_LAST)) {
		// SYMBOL_MAP_TYPE_BASE+nSymbolMapType = Symbol Map update (pHint = &LPCTSTR)
	}
}

void CFuncListView::FillFuncList()
{
	CListCtrl &theList = GetListCtrl();
	theList.DeleteAllItems();
	m_arrFileIndexes.RemoveAll();
	m_arrFuncIndexes.RemoveAll();

	if (m_nFileSet == -1) return;

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	int nFileCount = pDoc->GetFileCount(m_nFileSet);
	int nFuncCount;
	int i,j;
	int ndx, ndx2, ndx3;
	CFuncDescFile *pFuncDescFile;
	CFuncDesc *pFunc;
	CString strTemp;

	for (i=0; i<nFileCount; i++) {
		pFuncDescFile = pDoc->GetFuncDescFile(m_nFileSet, i);
		if (pFuncDescFile == NULL) continue;

		nFuncCount = pFuncDescFile->GetFuncCount();
		for (j=0; j<nFuncCount; j++) {
			pFunc = pFuncDescFile->GetFunc(j);
			if (pFunc == NULL) continue;

			ndx = theList.InsertItem(theList.GetItemCount(), pFunc->GetMainName());
			if (ndx == -1) continue;

			strTemp.Format("0x%04lX", pFunc->GetMainAddress());
			theList.SetItemText(ndx, 1, strTemp);

			ndx2 = m_arrFileIndexes.Add(i);
			ndx3 = m_arrFuncIndexes.Add(j);

			ASSERT(ndx2 == ndx3);

			theList.SetItemData(ndx, ndx2);
		}
	}

	ASSERT(m_arrFileIndexes.GetSize() == m_arrFuncIndexes.GetSize());
}

int CFuncListView::GetFileSetIndex()
{
	return m_nFileSet;
}

void CFuncListView::SetFileSetIndex(int nFileSet)
{
	m_nFileSet = nFileSet;
}

void CFuncListView::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	*pResult = 0;

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	CListCtrl &theList = GetListCtrl();
	int nSel = theList.GetNextItem(-1, LVNI_SELECTED);
	CFuncViewFuncRef aRef;

	if (nSel != -1) {
		aRef.m_pFile = pDoc->GetFuncDescFile(m_nFileSet, m_arrFileIndexes.GetAt(theList.GetItemData(nSel)));
		aRef.m_nIndex = m_arrFuncIndexes.GetAt(theList.GetItemData(nSel));
		pDoc->UpdateAllViews(this, FILESET_TYPE_BASE + m_nFileSet, &aRef);
	} else {
		aRef.m_pFile = NULL;
		aRef.m_nIndex = -1;
		pDoc->UpdateAllViews(this, FILESET_TYPE_BASE + m_nFileSet, &aRef);
	}
}

<file_sep>/README.md
![m6811dis logo](./programs/doc/6811chip.png)

**This repository has been displaced by the newer and more functional [Generic Code-Seeking Diassembler with Fuzzy-Function Analyzer](https://github.com/dewhisna/gendasm), which has all of the same functionality of this disassembler, plus adds other processors (like the AVR family) and has a functioning Fuzzy-Function Analyzer.**


Description
-----------


The M6811 Code-Seeking Disassembler is a command-line tool that lets you enter known starting vectors for a given code image for the 6811 micro. It will disassemble the code and follow through branches to assist in the separation of code and data.

Its companion Fuzzy Function Analyzer uses DNA Sequence Alignment Algorithms to locate similar code in multiple binaries, facilitating reverse-engineering.

Originally written to analyze code from GM automotive engine controllers, but is useful anywhere a 6811 micro is being used.

Version 1.0 was written in Borland Pascal in April 1996, and updated to v1.2 in June 1999. It was later rewritten to C++ in July 1999 through Jan 2000.

While it's been freely available since its creation, it's being released here as an open-source project so the world can better use it as it sees fit.

Version 2.0 is completely reworked in 2014 to compile and run with GCC and STL to make it fully portable and accessible to all computer platforms.

License
-------

M6811DIS Code-Seeking Disassembler

Copyright (C) 1996-2015 <NAME>, a.k.a. Dewtronics.

Contact: <http://www.dewtronics.com/>

<file_sep>/programs/funcanal/FuncView/FuncViewPrjDoc.h
// FuncViewPrjDoc.h : interface of the CFuncViewPrjDoc class
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncViewPrjDoc.h,v $
// Revision 1.1  2003/09/13 05:45:44  dewhisna
// Initial Revision
//
//

#if !defined(AFX_FUNCVIEWPRJDOC_H__3E867243_733D_48AF_9052_42CDC35AB42F__INCLUDED_)
#define AFX_FUNCVIEWPRJDOC_H__3E867243_733D_48AF_9052_42CDC35AB42F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "../funcdesc.h"

#define FILESET_TYPE_BASE 1000
#define FILESET_TYPE_LAST 1999
#define SYMBOL_MAP_TYPE_BASE 2000
#define SYMBOL_MAP_ALL 2000			// Used in updating all views with symbol table into
#define SYMBOL_MAP_LEFT_CODE 2001
#define SYMBOL_MAP_RIGHT_CODE 2002
#define SYMBOL_MAP_LEFT_DATA 2003
#define SYMBOL_MAP_RIGHT_DATA 2004
#define SYMBOL_MAP_TYPE_LAST 2999
#define MATRIX_TYPE_BASE 3000
#define MATRIX_TYPE_LAST 3999
#define COMP_DIFF_TYPE_BASE 4000
#define COMP_DIFF_TYPE_ALL 4000
#define COMP_DIFF_TYPE_LAST 4999

class CFuncViewFuncRef : public CObject
{
public:
	CFuncDescFile *m_pFile;			// Pointer to Function Description File
	int m_nIndex;					// Index to a specific function in File

	CFuncViewFuncRef() { Reset(); }
	void Reset() {
		m_pFile = NULL;
		m_nIndex = -1;
	}
	CFuncViewFuncRef& operator=(const CFuncViewFuncRef& aSrc)
	{
		m_pFile = aSrc.m_pFile;
		m_nIndex = aSrc.m_nIndex;
		return *this;
	}
};

class CFuncViewPrjDoc : public CDocument
{
protected: // create from serialization only
	CFuncViewPrjDoc();
	DECLARE_DYNCREATE(CFuncViewPrjDoc)

// Attributes
public:

// Operations
public:

protected:
	CFrameWnd *FindFrame(CRuntimeClass *pFrameClass);
	CFrameWnd *CreateFrame(UINT nIDResource, CRuntimeClass *pFrameClass, BOOL bDoInitialUpdate = TRUE);

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CFuncViewPrjDoc)
	public:
	virtual BOOL OnNewDocument();
	virtual void Serialize(CArchive& ar);
	virtual void DeleteContents();
	virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
	virtual BOOL OnSaveDocument(LPCTSTR lpszPathName);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CFuncViewPrjDoc();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif
	virtual void UpdateFrameCounts();

	enum FUNC_VIEW_FILE_SETS {
			FVFS_LEFT_FILES = 0,
			FVFS_RIGHT_FILES = 1,
			FVFS_COUNT = 2					// Always set to the number of file set types
	};

	int GetFileSetCount() const { return FVFS_COUNT; }
	CString GetFileSetDescription(int nFileSet);
	BOOL AddFile(int nFileSet, LPCTSTR pszFilePathName, CFile *pMsgFile = NULL, CFile *pErrFile = NULL);	// Loads and sets a new filename in the specified fileset
	int FindFile(int nFileSet, LPCTSTR pszFilePathName);	// Finds the specified file in the fileset, returning its 0-based index (or -1 if not found)
	BOOL RemoveFile(int nFileSet, int nIndex);				// Unloads and removes the specified file from the specified fileset
	int GetFileCount(int nFileSet);							// Returns the number of files in the specified set
	CString GetFilePathName(int nFileSet, int nIndex);		// Returns the specified file path name
	CString GetFileName(int nFileSet, int nIndex);			// Returns the specified file name
	CFuncDescFile *GetFuncDescFile(int nFileSet, int nIndex);	// Returns the specified function description
	int GetFuncCount(int nFileSet, int nIndex);				// Returns the number of functions in the specified file of the specified fileset or all functions in the set if index is -1

	CFuncDesc *GetNextFunction(int nFileSet, int &nFileIndex, int &nFuncIndex);
	CFuncDesc *GetFileFuncIndexFromLinearIndex(int nFileSet, int nLinearIndex, int &nFileIndex, int &nFuncIndex);		// Calculates/sets nFileIndex and nFuncIndex from a linear index and returns pointer to function

	CSymbolMap &GetSymbolMap() { return m_objSymbolMap; }

	void AddFunctionAssociation(LPCTSTR pszLeftFuncName, LPCTSTR pszRightFuncName);
	BOOL LookupLeftFuncAssociation(LPCTSTR pszLeftFuncName, CString &strRightFuncName);
	BOOL LookupRightFuncAssociation(LPCTSTR pszRightFuncName, CString &strLeftFuncName);

	CString &GetCompDiffText() { return m_strCompDiffText; }

	CString &GetOutputText() { return m_strOutputText; }

	CString GetMatrixPathName();
	void SetMatrixPathName(LPCTSTR pszPathName, BOOL bFreeCurrentMatrix);
	BOOL ReadOrBuildMatrix(BOOL bForceRebuild = FALSE);
	BOOL HaveMatrix();
	int GetMatrixRowCount() { return m_nMatrixRowCount; }
	int GetMatrixColumnCount() { return m_nMatrixColCount; }
	double **GetMatrix() { return m_ppnMatrix; }

protected:
	class CFileSet {
	public:
		void DeleteContents();
		BOOL AddFile(LPCTSTR pszFilePathName, CFile *pMsgFile = NULL, CFile *pErrFile = NULL, LPFUNCANALPROGRESSCALLBACK pfnCallback = NULL, LPARAM lParamCallback = 0);		// Loads and sets a new filename
		int FindFile(LPCTSTR pszFilePathName);		// Finds the specified file, returning its 0-based index (or -1 if not found)
		BOOL RemoveFile(int nIndex);				// Unloads and removes the specified file
		int GetFileCount();							// Returns the number of files
		CString GetFilePathName(int nIndex);		// Returns the specified file path name
		CString GetFileName(int nIndex);			// Returns the specified file name
		CFuncDescFile *GetFuncDescFile(int nIndex);	// Returns the specified function description
		int GetFuncCount(int nIndex);				// Returns the number of functions in the specified file or all files if index is -1
	protected:
		CFuncDescFileArray m_arrFuncDesc;			// Function Desc Files
	} m_arrFileSets[FVFS_COUNT];

	CSymbolMap m_objSymbolMap;
	CMapStringToString m_mapLeftToRightFunc;		// Mapping of left-hand to right-hand functions
	CMapStringToString m_mapRightToLeftFunc;		// Mapping of right-hand to left-hand functions

	CString m_strOutputText;

	BOOL m_bFileOpenInProgress;

	BOOL AllocateMatrixMemory();
	void FreeMatrixMemory();

	CString m_strMatrixPathName;
	int m_nMatrixRowCount;			// Comparison matrix row count (left files)
	int m_nMatrixColCount;			// Comparison matrix col count (right files)
	double **m_ppnMatrix;			// Comparison matrix data

	CString m_strCompDiffText;

private:
	static BOOL CALLBACK FuncDescFileProgressCallback(int nProgressPos, int nProgressMax, BOOL bAllowCancel, LPARAM lParam);

// Generated message map functions
protected:
	//{{AFX_MSG(CFuncViewPrjDoc)
	afx_msg void OnViewFuncDiff();
	afx_msg void OnUpdateViewFuncDiff(CCmdUI* pCmdUI);
	afx_msg void OnSymbolsReset();
	afx_msg void OnViewSymbolMap();
	afx_msg void OnUpdateViewSymbolMap(CCmdUI* pCmdUI);
	afx_msg void OnViewOutputWindow();
	afx_msg void OnUpdateViewOutputWindow(CCmdUI* pCmdUI);
	afx_msg void OnViewCompMatrix();
	afx_msg void OnUpdateViewCompMatrix(CCmdUI* pCmdUI);
	afx_msg void OnMatrixRebuild();
	afx_msg void OnMatrixRebuildForce();
	afx_msg void OnSymbolsExport();
	afx_msg void OnUpdateSymbolsExport(CCmdUI* pCmdUI);
	afx_msg void OnViewCompDiff();
	afx_msg void OnUpdateViewCompDiff(CCmdUI* pCmdUI);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_FUNCVIEWPRJDOC_H__3E867243_733D_48AF_9052_42CDC35AB42F__INCLUDED_)
<file_sep>/programs/m6811dis/bindfc.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      BINARYDFC -- Binary Data File Converter Class

      This is the C++ Binary DataFileConverter Object Class Header File.
      It is a child of the DFC Object class.

	  Author:  <NAME>
      Date:    March 7, 1997

      Written in: Borland C++ 4.52

      Updated: June 23, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

*/

#ifndef BINDFC_H
#define BINDFC_H

#include <iostream>
#include "dfc.h"
#include "memclass.h"
#include "errmsgs.h"


class TDFC_Binary : virtual public CDFCObject {
public:
	virtual std::string GetLibraryName(void) const { return "binary"; }
	virtual std::string GetShortDescription(void) const { return "Binary Data File Converter"; }
	virtual std::string GetDescription(void) const { return "Binary Data File Converter"; }

	virtual const char *DefaultExtension(void) const { return "bin"; }

	virtual int RetrieveFileMapping(std::istream *aFile, unsigned long NewBase, TMemRange *aRange) const;

	virtual int ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, unsigned char aDesc) const;

	virtual int WriteDataFile(std::ostream *aFile, TMemRange *aRange, unsigned long NewBase, TMemObject *aMemory,
						unsigned char aDesc, int UsePhysicalAddr, unsigned int FillMode) const;
};

#endif   // BINDFC_H

<file_sep>/programs/funcanal/stdafx.h
// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//
// $Log: stdafx.h,v $
// Revision 1.1  2002/07/01 05:50:02  dewhisna
// Initial Revision
//
//

#if !defined(AFX_STDAFX_H__8A6A4117_76AF_42B3_B639_E6120063A4C6__INCLUDED_)
#define AFX_STDAFX_H__8A6A4117_76AF_42B3_B639_E6120063A4C6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers

#include <afx.h>
//#include <afxwin.h>         // MFC core and standard components
//#include <afxext.h>         // MFC extensions
//#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls
//#ifndef _AFX_NO_AFXCMN_SUPPORT
//#include <afxcmn.h>			// MFC support for Windows Common Controls
//#endif // _AFX_NO_AFXCMN_SUPPORT
//
//#include <iostream>

#include <math.h>
#include <limits.h>
#include <float.h>
#include <afxtempl.h>		// Template Classes
#include <afxcoll.h>		// Collection Classes

#ifdef LINUX
#define cprintf printf
#include <unistd.h>
#else
#include <io.h>
#include <conio.h>
#endif

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__8A6A4117_76AF_42B3_B639_E6120063A4C6__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/SymbolMapListView.cpp
// SymbolMapListView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: SymbolMapListView.cpp,v $
// Revision 1.1  2003/09/13 05:45:49  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "SymbolMapListView.h"

#include "FuncViewPrjDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapListView

IMPLEMENT_DYNCREATE(CSymbolMapListView, CListView)

CSymbolMapListView::CSymbolMapListView()
{
}

CSymbolMapListView::~CSymbolMapListView()
{
}


BEGIN_MESSAGE_MAP(CSymbolMapListView, CListView)
	//{{AFX_MSG_MAP(CSymbolMapListView)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSymbolMapListView diagnostics

#ifdef _DEBUG
void CSymbolMapListView::AssertValid() const
{
	CListView::AssertValid();
}

void CSymbolMapListView::Dump(CDumpContext& dc) const
{
	CListView::Dump(dc);
}

CFuncViewPrjDoc* CSymbolMapListView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapListView message handlers

void CSymbolMapListView::OnInitialUpdate() 
{
	CListCtrl &theList = GetListCtrl();

	theList.ModifyStyle(0, LVS_NOSORTHEADER | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS, SWP_NOACTIVATE);
	theList.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

	theList.InsertColumn(0, "Symbol Name", LVCFMT_LEFT, 200, 0);
	theList.InsertColumn(1, "Hit Count", LVCFMT_RIGHT, 70, 1);
	theList.InsertColumn(2, "Hit Percent", LVCFMT_RIGHT, 100, 2);

	// Call the base OnInitialUpdate which will call OnUpdate which will call FillSymbolMapList:
	CListView::OnInitialUpdate();
}

void CSymbolMapListView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

	switch (lHint) {
		// SYMBOL_MAP_TYPE_BASE+nSymbolMapType = Symbol Map update (pHint = &LPCTSTR)
		case 0:						// Normal update
			FillSymbolMapList();
			break;

		case SYMBOL_MAP_LEFT_CODE:
		case SYMBOL_MAP_RIGHT_CODE:
		case SYMBOL_MAP_LEFT_DATA:
		case SYMBOL_MAP_RIGHT_DATA:
			FillSymbolMapList((DWORD)lHint, (LPCTSTR)pHint);
			break;

		case SYMBOL_MAP_ALL:		// If the whole list changes, clear view
			FillSymbolMapList();
			break;
	}
}

void CSymbolMapListView::FillSymbolMapList(DWORD nSource, LPCTSTR pszSymbolName)
{
	CListCtrl &theList = GetListCtrl();
	theList.DeleteAllItems();

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	CHeaderCtrl *pHeader = theList.GetHeaderCtrl();

	CString strSymbolName = pszSymbolName;

	DWORD nTotalHitCount = 0;
	CStringArray arrSymbols;
	CDWordArray arrHitCounts;
	CSymbolMap &theSymbols = pDoc->GetSymbolMap();
	CString strHeaderText;

	switch (nSource) {
		case SYMBOL_MAP_LEFT_CODE:
			nTotalHitCount = theSymbols.GetLeftSideCodeHitList(strSymbolName, arrSymbols, arrHitCounts);
			strHeaderText = "Right-Hand Code Symbol Name";
			break;

		case SYMBOL_MAP_RIGHT_CODE:
			nTotalHitCount = theSymbols.GetRightSideCodeHitList(strSymbolName, arrSymbols, arrHitCounts);
			strHeaderText = "Left-Hand Code Symbol Name";
			break;

		case SYMBOL_MAP_LEFT_DATA:
			nTotalHitCount = theSymbols.GetLeftSideDataHitList(strSymbolName, arrSymbols, arrHitCounts);
			strHeaderText = "Right-Hand Data Symbol Name";
			break;

		case SYMBOL_MAP_RIGHT_DATA:
			nTotalHitCount = theSymbols.GetRightSideDataHitList(strSymbolName, arrSymbols, arrHitCounts);
			strHeaderText = "Left-Hand Data Symbol Name";
			break;

		default:
			strHeaderText = "Symbol Name";
			break;
	}

	if (pHeader) {
		HDITEM theHeader;

		theHeader.mask = HDI_TEXT;
		theHeader.pszText = (LPTSTR)LPCTSTR(strHeaderText);
		theHeader.cchTextMax = strHeaderText.GetLength();
		pHeader->SetItem(0, &theHeader);
	}

	int ndx;
	int i;
	CString strTemp;

	ASSERT(arrSymbols.GetSize() == arrHitCounts.GetSize());		// These should have same number of members!
	for (i=0; i<arrSymbols.GetSize(); i++) {
		ASSERT(nTotalHitCount != 0);							// Should never have members with no hits!
		ndx = theList.InsertItem(i, arrSymbols.GetAt(i));
		if (ndx == -1) continue;

		strTemp.Format("%ld", arrHitCounts.GetAt(i));
		theList.SetItemText(i, 1, strTemp);

		strTemp.Format("%f%%", ((double)arrHitCounts.GetAt(i)/nTotalHitCount)*100);
		theList.SetItemText(i, 2, strTemp);
	}
}

<file_sep>/programs/funcanal/FuncView/StdAfx.cpp
// stdafx.cpp : source file that includes just the standard includes
//	FuncView.pch will be the pre-compiled header
//	stdafx.obj will contain the pre-compiled type information
//
// $Log: StdAfx.cpp,v $
// Revision 1.1  2003/09/13 05:45:49  dewhisna
// Initial Revision
//
//

#include "stdafx.h"



<file_sep>/programs/funcanal/FuncView/ChildFrm5.h
// ChildFrm5.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm5.h,v $
// Revision 1.1  2003/09/13 05:45:35  dewhisna
// Initial Revision
//
//

#if !defined(AFX_CHILDFRM5_H__BCBE933F_40AB_4822_9B37_535399CF6EBA__INCLUDED_)
#define AFX_CHILDFRM5_H__BCBE933F_40AB_4822_9B37_535399CF6EBA__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ChildFrmBase.h"

/////////////////////////////////////////////////////////////////////////////
// CChildFrame5 frame

class CChildFrame5 : public CChildFrameBase
{
	DECLARE_DYNCREATE(CChildFrame5)
protected:
	CChildFrame5();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CChildFrame5)
	protected:
	virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CChildFrame5();

	// Generated message map functions
	//{{AFX_MSG(CChildFrame5)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM5_H__BCBE933F_40AB_4822_9B37_535399CF6EBA__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/SymbolMapTreeView.h
// SymbolMapTreeView.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: SymbolMapTreeView.h,v $
// Revision 1.1  2003/09/13 05:45:51  dewhisna
// Initial Revision
//
//

#if !defined(AFX_SYMBOLMAPTREEVIEW_H__E57293FF_22E0_47C9_A41F_DAE7161BB334__INCLUDED_)
#define AFX_SYMBOLMAPTREEVIEW_H__E57293FF_22E0_47C9_A41F_DAE7161BB334__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CFuncViewPrjDoc;

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapTreeView view

class CSymbolMapTreeView : public CTreeView
{
protected:
	CSymbolMapTreeView();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(CSymbolMapTreeView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CSymbolMapTreeView)
	public:
	virtual void OnInitialUpdate();
	protected:
	virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CSymbolMapTreeView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:
	void FillSymbolMapList();
	void FillSymbolMapSubList(HTREEITEM hParent, CStringArray &aSymbolList, DWORD nItemData);

	// Generated message map functions
protected:
	//{{AFX_MSG(CSymbolMapTreeView)
	afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in SymbolMapTreeView.cpp
inline CFuncViewPrjDoc* CSymbolMapTreeView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_SYMBOLMAPTREEVIEW_H__E57293FF_22E0_47C9_A41F_DAE7161BB334__INCLUDED_)
<file_sep>/programs/m6811dis/errmsgs.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
 *    ERRMSGS
 *
 *    This file defines the acceptable "exception" messages for
 *    errorcode handling.
 *
 *    Author:  <NAME>
 *    Date:    July 20, 1997
 *
 *	This file was added as part of the rewrite process.
 */

#include "errmsgs.h"
#include <string>

// Preconstruct an out of memory error, cause if we run out of
//	memory, we may not have enough memory to construct it then.
EXCEPTION_ERROR _OUT_OF_MEMORY_EXCEPTION(0,
		EXCEPTION_ERROR::ERR_OUT_OF_MEMORY, 0, std::string());


EXCEPTION_ERROR::EXCEPTION_ERROR()
{
	delflag = 1;
	cause = EXCEPTION_ERROR::ERR_NONE;
	lcode = 0;
	name_ex.clear();
}

EXCEPTION_ERROR::EXCEPTION_ERROR(EXCEPTION_ERROR& anException)
{
	delflag = anException.delflag;
	cause = anException.cause;
	lcode = anException.lcode;
	name_ex = anException.name_ex;
}

EXCEPTION_ERROR::EXCEPTION_ERROR(int adelflag, const int acause, const unsigned long alcode, const std::string &anexname)
{
	delflag = adelflag;
	cause = acause;
	lcode = alcode;
	name_ex = anexname;
}
<file_sep>/programs/funcanal/funcanal.cpp
// funcanal.cpp : Defines the entry point for the console application.
//
// $Log: funcanal.cpp,v $
// Revision 1.4  2003/02/09 06:59:55  dewhisna
// Split comparison logic from Function File I/O
//
// Revision 1.3  2003/01/26 06:33:12  dewhisna
// Improved usage help
//
// Revision 1.2  2002/09/15 22:54:01  dewhisna
// Added Symbol Table comparison support
//
// Revision 1.1  2002/07/01 05:49:59  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "funcanal.h"
#include "funcdesc.h"
#include <ReadVer.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

void main(int argc, char* argv[])
{
	CProjectRCVersion aVerRC(::GetModuleHandle(NULL));
	CString strTemp;
	int nPos;
	WORD nVerMajor, nVerMinor;
	WORD nVerRev, nVerBuild;
	CStdioFile	FuncFile;
	CStdioFile	MatrixInFile;
	CStdioFile	MatrixOutFile;
	CStdioFile	DFROFile;
	CStdioFile	CompFile;
	CStdioFile	OESFile;
	CStdioFile	SymFile;
	CStdioFile	_StdOut(stdout);		// Make stdout into a CFile object for passing to parsers
	BOOL bNeedUsage;
	BOOL bOkFlag;
	CFuncDescFile *pFuncDescFileObj;
	int nReqArgs;
	int nMinReqInputFiles;
	int nArgPos;
	int i,j,k;
	int nTemp1, nTemp2;
	int cTemp;
	double **ppnCompResult;
	double nMaxCompResult;
	double nMinCompLimit;
	FUNC_COMPARE_METHOD nCompMethod;
	CFuncDescFile *pFuncFile1;
	CFuncDescFile *pFuncFile2;
	BOOL bFlag;
	CStringArray oes;
	BOOL bCompOESFlag;

	CSymbolMap aSymbolMap;

	CFuncDescFileArray m_FuncFiles;
	CString m_strMatrixInFilename;
	CString m_strMatrixOutFilename;
	CString m_strDFROFilename;
	CString m_strCompFilename;
	CString m_strOESFilename;
	CString m_strSymFilename;
	BOOL m_bForceOverwrite;

	if (aVerRC.GetInfo(VINFO_PRODUCTVERSION, strTemp)) {
		nVerRev = 0;
		nVerBuild = 0;

		nPos = strTemp.Find(",");
		if (nPos != -1) {
			nVerMajor = (WORD)strtoul(strTemp.Left(nPos), NULL, 0);
			strTemp = strTemp.Mid(nPos+1);
			nPos = strTemp.Find(",");
			if (nPos != - 1) {
				nVerMinor = (WORD)strtoul(strTemp.Left(nPos), NULL, 0);
				strTemp = strTemp.Mid(nPos+1);
				nPos = strTemp.Find(",");
				if (nPos != -1) {
					nVerRev = (WORD)strtoul(strTemp.Left(nPos), NULL, 0);
					nVerBuild = (WORD)strtoul(strTemp.Mid(nPos+1), NULL, 0);
				} else {
					nVerRev = (WORD)strtoul(strTemp, NULL, 0);
				}
			} else {
				nVerMinor = (WORD)strtoul(strTemp, NULL, 0);
			}
		} else {
			nVerMajor = (WORD)strtoul(strTemp, NULL, 0);
			nVerMinor = 0;
		}

		printf("Disassembler Function Analyzer V%d.%d", nVerMajor, nVerMinor);
		if (nVerRev) {
			printf(".%d", nVerRev);
		}
		printf(" (build %d)\n", nVerBuild);
	} else {
		printf("Disassembler Function Analyzer\n");
	}
	printf("Copyright(c)2002 by <NAME>\n");
	printf("\n");

	// Setup Defaults:
	m_strMatrixOutFilename = "";
	m_strDFROFilename = "";
	m_strCompFilename = "";
	m_strOESFilename = "";
	m_strSymFilename = "";
	m_bForceOverwrite = FALSE;

	bNeedUsage = FALSE;

	nReqArgs = 1;			// Must have at least program name
	nMinReqInputFiles = 1;	//		and one input filename (determine others below)
	nArgPos = 1;			// Start after the program name

	nMinCompLimit = 0;
	nCompMethod = FCM_DYNPROG_XDROP;

	bCompOESFlag = FALSE;

	while ((nArgPos < argc) && (!bNeedUsage)) {
		if ((argv[nArgPos][0] == '-') || (argv[nArgPos][0] == '/')) {
			switch (argv[nArgPos][1]) {
				case 'm':
					switch (argv[nArgPos][2]) {
						case 'i':			// Matrix Input File
							if (!m_strMatrixInFilename.IsEmpty()) {
								bNeedUsage = TRUE;
								continue;
							}
							if (strlen(argv[nArgPos]) > 3) {
								nReqArgs += 1;
								m_strMatrixInFilename = argv[nArgPos] + 3;
							} else {
								nReqArgs += 2;
								nArgPos++;
								if (nArgPos < argc) {
									m_strMatrixInFilename = argv[nArgPos];
								} else {
									bNeedUsage = TRUE;
								}
							}
							break;

						case 'o':			// Matrix Output File
							if (!m_strMatrixOutFilename.IsEmpty()) {
								bNeedUsage = TRUE;
								continue;
							}
							if (strlen(argv[nArgPos]) > 3) {
								nReqArgs += 1;
								m_strMatrixOutFilename = argv[nArgPos] + 3;
							} else {
								nReqArgs += 2;
								nArgPos++;
								if (nArgPos < argc) {
									m_strMatrixOutFilename = argv[nArgPos];
								} else {
									bNeedUsage = TRUE;
								}
							}
							nMinReqInputFiles = 2;		// Must have 2 input files
							break;

						default:
							bNeedUsage = TRUE;
							break;
					}
					break;

				case 'd':
					if (!m_strDFROFilename.IsEmpty()) {
						bNeedUsage = TRUE;
						continue;
					}
					if (strlen(argv[nArgPos]) > 2) {
						nReqArgs += 1;
						m_strDFROFilename = argv[nArgPos] + 2;
					} else {
						nReqArgs += 2;
						nArgPos++;
						if (nArgPos < argc) {
							m_strDFROFilename = argv[nArgPos];
						} else {
							bNeedUsage = TRUE;
						}
					}
					break;

				case 'c':
					switch (argv[nArgPos][2]) {
						case 'n':			// Normal Diff
						case 'e':			// Normal Diff with OES inline
							if (!m_strCompFilename.IsEmpty()) {
								bNeedUsage = TRUE;
								continue;
							}
							if (argv[nArgPos][2] == 'e') bCompOESFlag = TRUE;
							if (strlen(argv[nArgPos]) > 3) {
								nReqArgs += 1;
								m_strCompFilename = argv[nArgPos] + 3;
							} else {
								nReqArgs += 2;
								nArgPos++;
								if (nArgPos < argc) {
									m_strCompFilename = argv[nArgPos];
								} else {
									bNeedUsage = TRUE;
								}
							}
							nMinReqInputFiles = 2;		// Must have 2 input files
							break;

						default:
							bNeedUsage = TRUE;
							break;
					}
					break;

				case 'e':
					if (!m_strOESFilename.IsEmpty()) {
						bNeedUsage = TRUE;
						continue;
					}
					if (strlen(argv[nArgPos]) > 2) {
						nReqArgs += 1;
						m_strOESFilename = argv[nArgPos] + 2;
					} else {
						nReqArgs += 2;
						nArgPos++;
						if (nArgPos < argc) {
							m_strOESFilename = argv[nArgPos];
						} else {
							bNeedUsage = TRUE;
						}
					}
					nMinReqInputFiles = 2;		// Must have 2 input files
					break;

				case 's':
					if (!m_strSymFilename.IsEmpty()) {
						bNeedUsage = TRUE;
						continue;
					}
					if (strlen(argv[nArgPos]) > 2) {
						nReqArgs += 1;
						m_strSymFilename = argv[nArgPos] + 2;
					} else {
						nReqArgs += 2;
						nArgPos++;
						if (nArgPos < argc) {
							m_strSymFilename = argv[nArgPos];
						} else {
							bNeedUsage = TRUE;
						}
					}
					nMinReqInputFiles = 2;		// Must have 2 input files
					break;

				case 'f':
					m_bForceOverwrite = TRUE;
					nReqArgs++;
					break;

				case 'l':
					if (strlen(argv[nArgPos]) > 2) {
						nReqArgs += 1;
						nMinCompLimit = atof(argv[nArgPos] + 2)/100;
					} else {
						nReqArgs += 2;
						nArgPos++;
						if (nArgPos < argc) {
							nMinCompLimit = atof(argv[nArgPos])/100;
						} else {
							bNeedUsage = TRUE;
						}
					}
					break;

				case 'a':
					if (strlen(argv[nArgPos]) > 2) {
						nReqArgs += 1;
						nCompMethod = (FUNC_COMPARE_METHOD)strtoul(argv[nArgPos] + 2, NULL, 10);
					} else {
						nReqArgs += 2;
						nArgPos++;
						if (nArgPos < argc) {
							nCompMethod = (FUNC_COMPARE_METHOD)strtoul(argv[nArgPos], NULL, 10);
						} else {
							bNeedUsage = TRUE;
						}
					}
					switch (nCompMethod) {
						case FCM_DYNPROG_XDROP:
							printf("Using Comparison Algorithm: DynProg X-Drop\n\n");
							break;
						case FCM_DYNPROG_GREEDY:
							printf("Using Comparison Algorithm: DynProg Greedy\n\n");
							break;
					}
					break;

				default:
					bNeedUsage = TRUE;
					break;
			}
		} else {
			// If we get here and don't have another option, assume rest is filenames
			//		(nArgPos will be pointing to the first filename)
			break;
		}
		nArgPos++;
	}

	nReqArgs += nMinReqInputFiles;

	if ((!m_strMatrixInFilename.IsEmpty()) &&
		(!m_strMatrixOutFilename.IsEmpty())) bNeedUsage = TRUE;

	if ((m_strMatrixOutFilename.IsEmpty()) &&
		(m_strDFROFilename.IsEmpty()) &&
		(m_strCompFilename.IsEmpty()) &&
		(m_strOESFilename.IsEmpty()) &&
		(m_strSymFilename.IsEmpty())) {
		fprintf(stderr, "\n\nNothing to do...\n\n");
		bNeedUsage = TRUE;
	}

	bNeedUsage = bNeedUsage || (argc<nReqArgs);

	if (bNeedUsage) {
		printf("Usage:\n");
		printf("FuncAnal [-a <alg>] [-f] [-e <oes-fn>] [-s <sym-fn>] [-mi <mtx-fn> | -mo <mtx-fn>] [-d <dro-fn>] [-cn <cmp-fn> | -ce <cmp-fn>] [-l <limit>] <func-fn1> [<func-fn2>]\n");
		printf("\n");
		printf("Where:\n\n");
		printf("    <oes-fn>   = Output Optimal Edit Script Filename to generate\n\n");
		printf("    <mtx-fn>   = Input or Output Filename of a CSV file to read or to generate\n");
		printf("                 that denotes percentage of function cross-similarity.\n\n");
		printf("    <dro-fn>   = Output Filename of a file to generate that contains the\n");
		printf("                 diff-ready version all of the functions from the input file(s)\n\n");
		printf("    <cmp-fn>   = Output Filename of a file to generate that contains the full\n");
		printf("                 cross-functional comparisons.\n\n");
		printf("    <func-fn1> = Input Filename of the primary functions-definition-file.\n\n");
		printf("    <func-fn2> = Input Filename of the secondary functions-definition-file.\n");
		printf("                 (Optional only if not using -mo, -cX, -e, or -s)\n\n");
		printf("    <alg>      = Comparison algorithm to use.\n\n");
		printf("    <limit>    = Lower-Match Limit.\n\n");
		printf("\n");
		printf("At least one of the following switches must be used:\n");
		printf("    -mo <mtx-fn> Perform cross comparison of files and output a matrix of\n");
		printf("                 percent match (requires 2 input files). Cannot be used\n");
		printf("                 with the -mi switch.\n\n");
		printf("    -d <dro-fn>  Dump the functions definition file(s) in Diff-Ready notation\n\n");
		printf("    -cn <cmp-fn> Perform cross comparison of files and output a side-by-side\n");
		printf("                 diff of most similar functions (Normal Output)\n\n");
		printf("    -ce <cmp-fn> Perform cross comparison of files and output a side-by-side\n");
		printf("                 diff of most similar functions (Include inline OES)\n\n");
		printf("    -e <oes-fn>  Perform cross comparison of files and output an optimal edit\n");
		printf("                 script file that details the most optimal way of editing the\n");
		printf("                 left-most file to get the right-most file\n\n");
		printf("    -s <sym-fn>  Perform cross comparison of files and output a cross-map\n");
		printf("                 probability based symbol table\n\n");
		printf("\n");
		printf("The following switches can be specified but are optional:\n");
		printf("    -mi <mtx-fn> Reads the specified matrix file to get function cross\n");
		printf("                 comparison information rather than recalculating it.\n");
		printf("                 Cannot be used with the -mo switch.\n\n");
		printf("    -f           Force output file overwrite without prompting\n\n");
		printf("    -l <limit>   Minimum-Match Limit.  This option is only useful with the -cX,\n");
		printf("                 -e, and -s options and limits output to functions having a\n");
		printf("                 match percentage greater than or equal to this value.  If not\n");
		printf("                 specified, the minimum required match is anything greater than\n");
		printf("                 0%%. This value should be specified as a percentage or\n");
		printf("                 fraction of a percent.  For example: -l 50 matches anything\n");
		printf("                 50%% or higher.  -l 23.7 matches anything 23.7%% or higher.\n\n");
		printf("    -a <alg>     Select a specific comparison algorithm to use.  Where <alg> is\n");
		printf("                 one of the following:\n");
		printf("                       0 = Dynamic Programming X-Drop Algorithm\n");
		printf("                       1 = Dynamic Programming Greedy Algorithm\n");
		printf("                 If not specified, the X-Drop algorithm will be used.\n\n");
		printf("\n");
		_StdOut.m_pStream = NULL;	// prevent closing of stdout
		return;
	}

	if (!m_strMatrixOutFilename.IsEmpty()) {
		if ((!m_bForceOverwrite) && (access(m_strMatrixOutFilename, 0) == 0)) {
			fprintf(stderr, "\nFile \"%s\" exists! -- Overwrite? (y/n): ", LPCTSTR(m_strMatrixOutFilename));
#ifdef LINUX
			fflush(stdout);
			cTemp = toupper(getchar());
#else
			cTemp = toupper(getche());
#endif
			fprintf(stderr, "\n\n");
			if (cTemp != 'Y') {
				_StdOut.m_pStream = NULL;	// prevent closing of stdout
				return;
			}
		}
		if ((access(m_strMatrixOutFilename, 0) == 0) && (access(m_strMatrixOutFilename, 2) != 0)) {
			fprintf(stderr, "*** Error: Opening \"%s\" for writing...\n\n", LPCTSTR(m_strMatrixOutFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strDFROFilename.IsEmpty()) {
		if ((!m_bForceOverwrite) && (access(m_strDFROFilename, 0) == 0)) {
			fprintf(stderr, "\nFile \"%s\" exists! -- Overwrite? (y/n): ", LPCTSTR(m_strDFROFilename));
#ifdef LINUX
			fflush(stdout);
			cTemp = toupper(getchar());
#else
			cTemp = toupper(getche());
#endif
			fprintf(stderr, "\n\n");
			if (cTemp != 'Y') {
				_StdOut.m_pStream = NULL;	// prevent closing of stdout
				return;
			}
		}
		if ((access(m_strDFROFilename, 0) == 0) && (access(m_strDFROFilename, 2)!=0)) {
			fprintf(stderr, "*** Error: Opening \"%s\" for writing...\n\n", LPCTSTR(m_strDFROFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strCompFilename.IsEmpty()) {
		if ((!m_bForceOverwrite) && (access(m_strCompFilename, 0) == 0)) {
			fprintf(stderr, "\nFile \"%s\" exists! -- Overwrite? (y/n): ", LPCTSTR(m_strCompFilename));
#ifdef LINUX
			fflush(stdout);
			cTemp = toupper(getchar());
#else
			cTemp = toupper(getche());
#endif
			fprintf(stderr, "\n\n");
			if (cTemp != 'Y') {
				_StdOut.m_pStream = NULL;	// prevent closing of stdout
				return;
			}
		}
		if ((access(m_strCompFilename, 0) == 0) && (access(m_strCompFilename, 2)!=0)) {
			fprintf(stderr, "*** Error: Opening \"%s\" for writing...\n\n", LPCTSTR(m_strCompFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strOESFilename.IsEmpty()) {
		if ((!m_bForceOverwrite) && (access(m_strOESFilename, 0) == 0)) {
			fprintf(stderr, "\nFile \"%s\" exists! -- Overwrite? (y/n): ", LPCTSTR(m_strOESFilename));
#ifdef LINUX
			fflush(stdout);
			cTemp = toupper(getchar());
#else
			cTemp = toupper(getche());
#endif
			fprintf(stderr, "\n\n");
			if (cTemp != 'Y') {
				_StdOut.m_pStream = NULL;	// prevent closing of stdout
				return;
			}
		}
		if ((access(m_strOESFilename, 0) == 0) && (access(m_strOESFilename, 2)!=0)) {
			fprintf(stderr, "*** Error: Opening \"%s\" for writing...\n\n", LPCTSTR(m_strOESFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strSymFilename.IsEmpty()) {
		if ((!m_bForceOverwrite) && (access(m_strSymFilename, 0) == 0)) {
			fprintf(stderr, "\nFile \"%s\" exists! -- Overwrite? (y/n): ", LPCTSTR(m_strSymFilename));
#ifdef LINUX
			fflush(stdout);
			cTemp = toupper(getchar());
#else
			cTemp = toupper(getche());
#endif
			fprintf(stderr, "\n\n");
			if (cTemp != 'Y') {
				_StdOut.m_pStream = NULL;	// prevent closing of stdout
				return;
			}
		}
		if ((access(m_strSymFilename, 0) == 0) && (access(m_strSymFilename, 2)!=0)) {
			fprintf(stderr, "*** Error: Opening \"%s\" for writing...\n\n", LPCTSTR(m_strSymFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strMatrixOutFilename.IsEmpty()) {
		if (!MatrixOutFile.Open(m_strMatrixOutFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareExclusive)) {
			fprintf(stderr, "*** Error: Opening Matrix Output File \"%s\" for writing...\n", LPCTSTR(m_strMatrixOutFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strDFROFilename.IsEmpty()) {
		if (!DFROFile.Open(m_strDFROFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareExclusive)) {
			fprintf(stderr, "*** Error: Opening Diff-Ready Output File \"%s\" for writing...\n", LPCTSTR(m_strDFROFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strCompFilename.IsEmpty()) {
		if (!CompFile.Open(m_strCompFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareExclusive)) {
			fprintf(stderr, "*** Error: Opening Compare Output File \"%s\" for writing...\n", LPCTSTR(m_strCompFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strOESFilename.IsEmpty()) {
		if (!OESFile.Open(m_strOESFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareExclusive)) {
			fprintf(stderr, "*** Error: Opening Optimal Edit Script Output File \"%s\" for writing...\n", LPCTSTR(m_strOESFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	if (!m_strSymFilename.IsEmpty()) {
		if (!SymFile.Open(m_strSymFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareExclusive)) {
			fprintf(stderr, "*** Error: Opening Symbol Table Output File \"%s\" for writing...\n", LPCTSTR(m_strSymFilename));
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
	}

	bOkFlag = TRUE;
	while ((bOkFlag) && (nArgPos < argc)) {
		pFuncDescFileObj = new CFuncDescFile;
		if (pFuncDescFileObj == NULL) {
			fprintf(stderr, "*** Error: Out of Memory or Failure Creating FuncDescFile Object...\n");
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
		m_FuncFiles.Add(pFuncDescFileObj);

		if (!FuncFile.Open(argv[nArgPos], CFile::modeRead | CFile::typeText | CFile::shareDenyWrite)) {
			fprintf(stderr, "*** Error: Opening Function Definition File \"%s\" for reading...\n", argv[nArgPos]);
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
		bOkFlag = pFuncDescFileObj->ReadFuncDescFile(FuncFile, &_StdOut, &_StdOut);
		FuncFile.Close();
		nArgPos++;

		if (!m_strDFROFilename.IsEmpty()) {
			for (i=0; i<pFuncDescFileObj->GetFuncCount(); i++) {
				strTemp.Format("File \"%s\" Function \"%s\" (%ld):\n",
										LPCTSTR(pFuncDescFileObj->GetFuncFileName()),
										LPCTSTR(pFuncDescFileObj->GetFunc(i)->GetMainName()),
										i+1);
				DFROFile.WriteString(strTemp);
				DFROFile.WriteString(pFuncDescFileObj->GetFunc(i)->ExportToDiff());
				DFROFile.WriteString("\n\n");
			}
		}
	}


//m_FuncFiles.CompareFunctions(CFuncDescFileArray::FCM_DYNPROG_GREEDY, 0, 31, 1, 32,TRUE);
//_StdOut.m_pStream = NULL;	// prevent closing of stdout
//return;

	if ((!m_strMatrixOutFilename.IsEmpty()) ||
		(!m_strCompFilename.IsEmpty()) ||
		(!m_strOESFilename.IsEmpty()) ||
		(!m_strSymFilename.IsEmpty())) {

		if (m_strMatrixInFilename.IsEmpty()) {
			printf("Cross-Comparing Functions...\n");
		} else {
			printf("Using specified Cross-Comparison Matrix File: \"%s\"...\n", LPCTSTR(m_strMatrixInFilename));
			if (!MatrixInFile.Open(m_strMatrixInFilename, CFile::modeRead | CFile::typeText | CFile::shareDenyWrite)) {
				fprintf(stderr, "*** Error: Opening Matrix Input File \"%s\" for reading...\n", LPCTSTR(m_strMatrixInFilename));

				_StdOut.m_pStream = NULL;	// prevent closing of stdout
				return;
			}
		}

		pFuncFile1 = m_FuncFiles.GetAt(0);
		pFuncFile2 = m_FuncFiles.GetAt(1);

		// Allocate Memory:
		ppnCompResult = new double*[pFuncFile1->GetFuncCount()];
		if (ppnCompResult == NULL) {
			AfxThrowMemoryException();
			_StdOut.m_pStream = NULL;	// prevent closing of stdout
			return;
		}
		for (i=0; i<pFuncFile1->GetFuncCount(); i++) {
			ppnCompResult[i] = new double[pFuncFile2->GetFuncCount()];
			if (ppnCompResult[i] == NULL) AfxThrowMemoryException();
		}

		if (!m_strMatrixInFilename.IsEmpty()) {
			// If we have a MatrixIn file, read cross compare info:
			strTemp = "";
			MatrixInFile.ReadString(strTemp);
			strTemp.TrimLeft();
			strTemp.TrimRight();
			nPos = strTemp.Find(',');
			if (nPos != -1) {
				nTemp1 = atoi(strTemp.Left(nPos));
				nTemp2 = atoi(strTemp.Mid(nPos + 1));
			} else {
				nTemp1 = atoi(strTemp);
				nTemp2 = 0;
			}
			if ((nTemp1 != pFuncFile1->GetFuncCount()) ||
				(nTemp2 != pFuncFile2->GetFuncCount())) {
				fprintf(stderr, "*** Warning: Specified Input Matrix File doesn't match\n");
				fprintf(stderr, "        the specified function description files.  A full\n");
				fprintf(stderr, "        cross-comparison will be performed!\n\n");
				m_strMatrixInFilename.Empty();
			} else {
				MatrixInFile.ReadString(strTemp);		// Read and toss x break-points line
				for (i=0; i<pFuncFile1->GetFuncCount(); i++) {
					strTemp = "";
					MatrixInFile.ReadString(strTemp);
					strTemp.TrimLeft();
					strTemp.TrimRight();
					nPos = strTemp.Find(',');
					strTemp = strTemp.Mid(nPos+1);		// Toss y break-point
					for (j=0; j<pFuncFile2->GetFuncCount(); j++) {
						nPos = strTemp.Find(',');
						if (nPos != -1) {
							ppnCompResult[i][j] = atof(strTemp.Left(nPos));
							strTemp = strTemp.Mid(nPos+1);
							strTemp.TrimLeft();
						} else {
							ppnCompResult[i][j] = atof(strTemp);
							strTemp = "";
						}
					}
				}
			}

			MatrixInFile.Close();
		}

		if (m_strMatrixInFilename.IsEmpty()) {
			// If no MatrixIn file was specified, do complete cross comparison:
			fprintf(stderr, "Please Wait");
			if (!m_strMatrixOutFilename.IsEmpty()) {
				strTemp.Format("%ld,%ld\n", pFuncFile1->GetFuncCount(), pFuncFile2->GetFuncCount());
				MatrixOutFile.WriteString(strTemp);
				for (j=0; j<pFuncFile2->GetFuncCount(); j++) {
					strTemp.Format(",%ld", j+1);
					MatrixOutFile.WriteString(strTemp);
				}
			}
			if (!m_strMatrixOutFilename.IsEmpty()) MatrixOutFile.WriteString("\n");
			for (i=0; i<pFuncFile1->GetFuncCount(); i++) {
				fprintf(stderr, ".");
				if (!m_strMatrixOutFilename.IsEmpty()) {
					strTemp.Format("%ld", i+1);
					MatrixOutFile.WriteString(strTemp);
				}
				for (j=0; j<pFuncFile2->GetFuncCount(); j++) {
					ppnCompResult[i][j] = CompareFunctions(nCompMethod, pFuncFile1, i, pFuncFile2, j, FALSE);
					if (!m_strMatrixOutFilename.IsEmpty()) {
						strTemp.Format(",%.12g", ppnCompResult[i][j]);
						MatrixOutFile.WriteString(strTemp);
					}
				}
				if (!m_strMatrixOutFilename.IsEmpty()) MatrixOutFile.WriteString("\n");
			}
			fprintf(stderr, "\n\n");
		}

		printf("\nBest Matches:\n");

		if (!m_strCompFilename.IsEmpty()) {
			CompFile.WriteString("Left Filename  : ");
			CompFile.WriteString(pFuncFile1->GetFuncPathName() + "\n");
			CompFile.WriteString("Right Filename : ");
			CompFile.WriteString(pFuncFile2->GetFuncPathName() + "\n");
			CompFile.WriteString("\n");
		}

		if (!m_strOESFilename.IsEmpty()) {
			OESFile.WriteString("; Left Filename  : ");
			OESFile.WriteString(pFuncFile1->GetFuncPathName() + "\n");
			OESFile.WriteString("; Right Filename : ");
			OESFile.WriteString(pFuncFile2->GetFuncPathName() + "\n");
		}

		if (!m_strSymFilename.IsEmpty()) {
			SymFile.WriteString("; Left Filename  : ");
			SymFile.WriteString(pFuncFile1->GetFuncPathName() + "\n");
			SymFile.WriteString("; Right Filename : ");
			SymFile.WriteString(pFuncFile2->GetFuncPathName() + "\n");
		}

		aSymbolMap.FreeAll();

		for (i=0; i<pFuncFile1->GetFuncCount(); i++) {
			nMaxCompResult = 0;
			for (j=0; j<pFuncFile2->GetFuncCount(); j++) nMaxCompResult = __max(nMaxCompResult, ppnCompResult[i][j]);
			bFlag = FALSE;
			if ((nMaxCompResult > 0) && (nMaxCompResult >= nMinCompLimit)) {
				printf("    %s : ", LPCTSTR(PadString(pFuncFile1->GetFunc(i)->GetMainName(), CFuncObject::GetFieldWidth(CFuncObject::FC_LABEL))));
				for (j=0; j<pFuncFile2->GetFuncCount(); j++) {
					if (ppnCompResult[i][j] < nMaxCompResult) continue;

					if (bFlag) {
						if (!m_strCompFilename.IsEmpty()) {
							CompFile.WriteString("\n\n");
						}
						printf(", ");
					} else {
						if (!m_strCompFilename.IsEmpty()) {
							CompFile.WriteString("================================================================================\n");
						}
					}
					bFlag = TRUE;

					printf("%s", LPCTSTR(pFuncFile2->GetFunc(j)->GetMainName()));

					if (!m_strCompFilename.IsEmpty()) {
						CompFile.WriteString("--------------------------------------------------------------------------------\n");
						strTemp.Format("    Left Function  : %s (%ld)\n    Right Function : %s (%ld)\n    Matches by     : %f%%\n",
										LPCTSTR(pFuncFile1->GetFunc(i)->GetMainName()), i+1,
										LPCTSTR(pFuncFile2->GetFunc(j)->GetMainName()), j+1,
										ppnCompResult[i][j]*100);
						CompFile.WriteString(strTemp);
						CompFile.WriteString("--------------------------------------------------------------------------------\n");
						strTemp = DiffFunctions(nCompMethod, pFuncFile1, i, pFuncFile2, j, &aSymbolMap);
						if (bCompOESFlag) {
							if (GetLastEditScript(oes)) {
								for (k=0; k<oes.GetSize(); k++) {
									CompFile.WriteString(oes.GetAt(k) + "\n");
								}
							}
							CompFile.WriteString("--------------------------------------------------------------------------------\n");
						}
						CompFile.WriteString(strTemp);
						CompFile.WriteString("--------------------------------------------------------------------------------\n");
					}

					if (!m_strOESFilename.IsEmpty()) {
						CompareFunctions(nCompMethod, pFuncFile1, i, pFuncFile2, j, TRUE);
						if (GetLastEditScript(oes)) {
							OESFile.WriteString("\n");
							strTemp.Format("@%s(%ld)|%s(%ld)\n",
										LPCTSTR(pFuncFile1->GetFunc(i)->GetMainName()), i+1,
										LPCTSTR(pFuncFile2->GetFunc(j)->GetMainName()), j+1);
							OESFile.WriteString(strTemp);
							for (k=0; k<oes.GetSize(); k++) {
								OESFile.WriteString(oes.GetAt(k) + "\n");
							}
						}
					}
				}
				if (!m_strCompFilename.IsEmpty()) {
					CompFile.WriteString("================================================================================\n\n\n");
				}
				printf(" : (%f%%)", nMaxCompResult * 100);
				printf("\n");
			}
		}

		printf("\nFunctions in \"%s\" with No Matches:\n", LPCTSTR(pFuncFile1->GetFuncPathName()));
		bFlag = TRUE;
		for (i=0; i<pFuncFile1->GetFuncCount(); i++) {
			nMaxCompResult = 0;
			for (j=0; j<pFuncFile2->GetFuncCount(); j++) nMaxCompResult = __max(nMaxCompResult, ppnCompResult[i][j]);
			if ((nMaxCompResult <= 0) || (nMaxCompResult < nMinCompLimit)) {
				printf("    %s\n", LPCTSTR(pFuncFile1->GetFunc(i)->GetMainName()));
				bFlag = FALSE;
			}
		}
		if (bFlag) printf("    <None>\n");

		printf("\nFunctions in \"%s\" with No Matches:\n", LPCTSTR(pFuncFile2->GetFuncPathName()));
		bFlag = TRUE;
		for (j=0; j<pFuncFile2->GetFuncCount(); j++) {
			nMaxCompResult = 0;
			for (i=0; i<pFuncFile1->GetFuncCount(); i++) nMaxCompResult = __max(nMaxCompResult, ppnCompResult[i][j]);
			if ((nMaxCompResult <= 0) || (nMaxCompResult < nMinCompLimit)) {
				printf("    %s\n", LPCTSTR(pFuncFile2->GetFunc(j)->GetMainName()));
				bFlag = FALSE;
			}
		}
		if (bFlag) printf("    <None>\n");

		// Dump Symbol Tables:
		CStringArray arrSymbolList;
		CStringArray arrHitList;
		CDWordArray arrHitCount;
		DWORD nTotalHits;
		int nSymWidth;

		printf("\nCross-Comparing Symbol Tables...\n");

		printf("\nLeft-Side Code Symbol Matches:\n");
		printf("------------------------------\n");
		if (!m_strSymFilename.IsEmpty()) {
			SymFile.WriteString("\nLeft-Side Code Symbol Matches:\n");
			SymFile.WriteString("------------------------------\n");
		}
		aSymbolMap.GetLeftSideCodeSymbolList(arrSymbolList);
		nSymWidth = 0;
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			if (arrSymbolList.GetAt(i).GetLength() > nSymWidth) nSymWidth = arrSymbolList.GetAt(i).GetLength();
		}
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			nTotalHits = aSymbolMap.GetLeftSideCodeHitList(arrSymbolList.GetAt(i), arrHitList, arrHitCount);
			ASSERT(arrHitList.GetSize() == arrHitCount.GetSize());
			strTemp = arrSymbolList.GetAt(i);
			for (j=0; j<(nSymWidth-arrSymbolList.GetAt(i).GetLength()); j++) strTemp += ' ';
			printf("%s : ", LPCTSTR(strTemp));
			if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp + " : ");
			if (arrHitList.GetSize() > 0) {
				if (nTotalHits == 0) nTotalHits = 1;	// Safe-guard for divide by zero
				for (j=0; j<arrHitList.GetSize(); j++) {
					if (arrHitList.GetAt(j).IsEmpty()) arrHitList.SetAt(j, "???");
					strTemp.Format("%s%s (%f%%)", ((j!=0) ? ", " : ""), LPCTSTR(arrHitList.GetAt(j)),
										((double)arrHitCount.GetAt(j)/nTotalHits)*100);
					printf("%s", LPCTSTR(strTemp));
					if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp);
				}
				printf("\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("\n");
			} else {
				printf("<none>\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("<none>\n");
			}
		}

		printf("\nLeft-Side Data Symbol Matches:\n");
		printf("------------------------------\n");
		if (!m_strSymFilename.IsEmpty()) {
			SymFile.WriteString("\nLeft-Side Data Symbol Matches:\n");
			SymFile.WriteString("------------------------------\n");
		}
		aSymbolMap.GetLeftSideDataSymbolList(arrSymbolList);
		nSymWidth = 0;
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			if (arrSymbolList.GetAt(i).GetLength() > nSymWidth) nSymWidth = arrSymbolList.GetAt(i).GetLength();
		}
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			nTotalHits = aSymbolMap.GetLeftSideDataHitList(arrSymbolList.GetAt(i), arrHitList, arrHitCount);
			ASSERT(arrHitList.GetSize() == arrHitCount.GetSize());
			strTemp = arrSymbolList.GetAt(i);
			for (j=0; j<(nSymWidth-arrSymbolList.GetAt(i).GetLength()); j++) strTemp += ' ';
			printf("%s : ", LPCTSTR(strTemp));
			if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp + " : ");
			if (arrHitList.GetSize() > 0) {
				if (nTotalHits == 0) nTotalHits = 1;	// Safe-guard for divide by zero
				for (j=0; j<arrHitList.GetSize(); j++) {
					if (arrHitList.GetAt(j).IsEmpty()) arrHitList.SetAt(j, "???");
					strTemp.Format("%s%s (%f%%)", ((j!=0) ? ", " : ""), LPCTSTR(arrHitList.GetAt(j)),
										((double)arrHitCount.GetAt(j)/nTotalHits)*100);
					printf("%s", LPCTSTR(strTemp));
					if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp);
				}
				printf("\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("\n");
			} else {
				printf("<none>\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("<none>\n");
			}
		}

		printf("\nRight-Side Code Symbol Matches:\n");
		printf("-------------------------------\n");
		if (!m_strSymFilename.IsEmpty()) {
			SymFile.WriteString("\nRight-Side Code Symbol Matches:\n");
			SymFile.WriteString("-------------------------------\n");
		}
		aSymbolMap.GetRightSideCodeSymbolList(arrSymbolList);
		nSymWidth = 0;
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			if (arrSymbolList.GetAt(i).GetLength() > nSymWidth) nSymWidth = arrSymbolList.GetAt(i).GetLength();
		}
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			nTotalHits = aSymbolMap.GetRightSideCodeHitList(arrSymbolList.GetAt(i), arrHitList, arrHitCount);
			ASSERT(arrHitList.GetSize() == arrHitCount.GetSize());
			strTemp = arrSymbolList.GetAt(i);
			for (j=0; j<(nSymWidth-arrSymbolList.GetAt(i).GetLength()); j++) strTemp += ' ';
			printf("%s : ", LPCTSTR(strTemp));
			if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp + " : ");
			if (arrHitList.GetSize() > 0) {
				if (nTotalHits == 0) nTotalHits = 1;	// Safe-guard for divide by zero
				for (j=0; j<arrHitList.GetSize(); j++) {
					if (arrHitList.GetAt(j).IsEmpty()) arrHitList.SetAt(j, "???");
					strTemp.Format("%s%s (%f%%)", ((j!=0) ? ", " : ""), LPCTSTR(arrHitList.GetAt(j)),
										((double)arrHitCount.GetAt(j)/nTotalHits)*100);
					printf("%s", LPCTSTR(strTemp));
					if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp);
				}
				printf("\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("\n");
			} else {
				printf("<none>\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("<none>\n");
			}
		}

		printf("\nRight-Side Data Symbol Matches:\n");
		printf("-------------------------------\n");
		if (!m_strSymFilename.IsEmpty()) {
			SymFile.WriteString("\nRight-Side Data Symbol Matches:\n");
			SymFile.WriteString("-------------------------------\n");
		}
		aSymbolMap.GetRightSideDataSymbolList(arrSymbolList);
		nSymWidth = 0;
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			if (arrSymbolList.GetAt(i).GetLength() > nSymWidth) nSymWidth = arrSymbolList.GetAt(i).GetLength();
		}
		for (i=0; i<arrSymbolList.GetSize(); i++) {
			nTotalHits = aSymbolMap.GetRightSideDataHitList(arrSymbolList.GetAt(i), arrHitList, arrHitCount);
			ASSERT(arrHitList.GetSize() == arrHitCount.GetSize());
			strTemp = arrSymbolList.GetAt(i);
			for (j=0; j<(nSymWidth-arrSymbolList.GetAt(i).GetLength()); j++) strTemp += ' ';
			printf("%s : ", LPCTSTR(strTemp));
			if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp + " : ");
			if (arrHitList.GetSize() > 0) {
				if (nTotalHits == 0) nTotalHits = 1;	// Safe-guard for divide by zero
				for (j=0; j<arrHitList.GetSize(); j++) {
					if (arrHitList.GetAt(j).IsEmpty()) arrHitList.SetAt(j, "???");
					strTemp.Format("%s%s (%f%%)", ((j!=0) ? ", " : ""), LPCTSTR(arrHitList.GetAt(j)),
										((double)arrHitCount.GetAt(j)/nTotalHits)*100);
					printf("%s", LPCTSTR(strTemp));
					if (!m_strSymFilename.IsEmpty()) SymFile.WriteString(strTemp);
				}
				printf("\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("\n");
			} else {
				printf("<none>\n");
				if (!m_strSymFilename.IsEmpty()) SymFile.WriteString("<none>\n");
			}
		}

		// Deallocate Memory:
		for (i=0; i<pFuncFile1->GetFuncCount(); i++) delete[] (ppnCompResult[i]);
		delete[] ppnCompResult;
	}

	printf("\nFunction Analysis Complete...\n\n");

	if (!m_strMatrixOutFilename.IsEmpty()) MatrixOutFile.Close();
	if (!m_strDFROFilename.IsEmpty()) DFROFile.Close();
	if (!m_strCompFilename.IsEmpty()) CompFile.Close();
	if (!m_strOESFilename.IsEmpty()) OESFile.Close();
	if (!m_strSymFilename.IsEmpty()) SymFile.Close();

	_StdOut.m_pStream = NULL;	// prevent closing of stdout
}


<file_sep>/programs/funcanal/FuncView/CompDiffEditView.cpp
// CompDiffEditView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: CompDiffEditView.cpp,v $
// Revision 1.1  2003/09/13 05:45:37  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "FuncViewPrjDoc.h"
#include "CompDiffEditView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCompDiffEditView

IMPLEMENT_DYNCREATE(CCompDiffEditView, CEditView)

CCompDiffEditView::CCompDiffEditView()
{
	m_fntEditor.CreatePointFont(100, "Courier New");
}

CCompDiffEditView::~CCompDiffEditView()
{
}


BEGIN_MESSAGE_MAP(CCompDiffEditView, CEditView)
	//{{AFX_MSG_MAP(CCompDiffEditView)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CCompDiffEditView diagnostics

#ifdef _DEBUG
void CCompDiffEditView::AssertValid() const
{
	CEditView::AssertValid();
}

void CCompDiffEditView::Dump(CDumpContext& dc) const
{
	CEditView::Dump(dc);
}

CFuncViewPrjDoc* CCompDiffEditView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CCompDiffEditView message handlers

void CCompDiffEditView::OnInitialUpdate() 
{
	CEdit &theEdit = GetEditCtrl();

	theEdit.SetFont(&m_fntEditor);
	theEdit.SetReadOnly(TRUE);

	CEditView::OnInitialUpdate();	// This calls OnUpdate
}

void CCompDiffEditView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

	CEdit &theEdit = GetEditCtrl();

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) {
		theEdit.SetWindowText("");
		return;
	}

	if ((lHint == 0) ||
		((lHint >= COMP_DIFF_TYPE_BASE) && (lHint <= COMP_DIFF_TYPE_LAST))) {

		// Convert LF's to CRLF's so editor will display them correctly:
		CString strTemp = pDoc->GetCompDiffText();
		CString strTemp2 = "";
		int pos;

		while (!strTemp.IsEmpty()) {
			pos = strTemp.Find('\n');
			if (pos != -1) {
				strTemp2 += strTemp.Left(pos);
				strTemp2 += "\r\n";
				strTemp = strTemp.Mid(pos+1);
			} else {
				strTemp2 += strTemp;
				strTemp = "";
			}
		}

		theEdit.SetWindowText(strTemp2);
	}
}

<file_sep>/programs/m6811dis/m6811dis.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

//
//	Header for M6811DIS
//


#ifndef _M6811DIS_H_
#define _M6811DIS_H_





#endif	// _M6811DIS_H_
<file_sep>/programs/funcanal/FuncView/ChildFrm3.cpp
// ChildFrm3.cpp : implementation file
//
// Frame Window for the Symbol Map Views
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm3.cpp,v $
// Revision 1.1  2003/09/13 05:45:33  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "ChildFrm3.h"

#include "SymbolMapTreeView.h"
#include "SymbolMapListView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChildFrame3

IMPLEMENT_DYNCREATE(CChildFrame3, CChildFrameBase)

CChildFrame3::CChildFrame3()
{
}

CChildFrame3::~CChildFrame3()
{
}


BEGIN_MESSAGE_MAP(CChildFrame3, CChildFrameBase)
	//{{AFX_MSG_MAP(CChildFrame3)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildFrame3 message handlers

BOOL CChildFrame3::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	if (!m_wndSplitter.CreateStatic(this, 1, 2)) return FALSE;

	if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CSymbolMapTreeView), CSize(300, 0), pContext)) return FALSE;
	if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CSymbolMapListView), CSize(300, 0), pContext)) return FALSE;

	return TRUE;

//	return CChildFrameBase::OnCreateClient(lpcs, pContext);
}

<file_sep>/programs/m6811dis/m6811gdc.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

//
//	M6811GDC -- This is the implementation for the M6811 Disassembler GDC module
//
//
//	Groups: (Grp) : xy
//	  Where x (msnb = destination = FIRST operand)
//			y (lsnb = source = LAST operand)
//
//			0 = opcode only, nothing follows
//			1 = 8-bit absolute address follows only
//			2 = 16-bit absolute address follows only
//			3 = 8-bit relative address follows only
//			4 = 16-bit relative address follows only		(Not used on HC11)
//			5 = 8-bit data follows only
//			6 = 16-bit data follows only
//			7 = 8-bit absolute address followed by 8-bit mask
//			8 = 8-bit X offset address followed by 8-bit mask
//			9 = 8-bit Y offset address followed by 8-bit mask
//			A = 8-bit X offset address
//			B = 8-bit Y offset address
//
//	Control: (Algorithm control) : xy
//	  Where x (msnb = destination = FIRST operand)
//			y (lsnb = source = LAST operand)
//
//			0 = Disassemble as code
//
//			1 = Disassemble as code, with data addr label
//					(on opcodes with post-byte, label generation is dependent upon post-byte value.)
//
//			2 = Disassemble as undeterminable branch address (Comment code)
//
//			3 = Disassemble as determinable branch, add branch addr and label
//
//			4 = Disassemble as conditionally undeterminable branch address (Comment code),
//					with data addr label, (on opcodes with post-byte, label generation is dependent
//					upon post-byte value. conditional upon post-byte)
//
//	This version setup for compatibility with the AS6811 assembler
//

//
//	Format of Function Output File:
//
//		Any line beginning with a ";" is considered to be a commment line and is ignored
//
//		Memory Mapping:
//			#type|addr|size
//			   |    |    |____  Size of Mapped area (hex)
//			   |    |_________  Absolute Address of Mapped area (hex)
//			   |______________  Type of Mapped area (One of following: ROM, RAM, IO)
//
//		Label Definitions:
//			!addr|label
//			   |    |____ Label(s) for this address(comma separated)
//			   |_________ Absolute Address (hex)
//
//		Start of New Function:
//			@xxxx|name
//			   |    |____ Name(s) of Function (comma separated list)
//			   |_________ Absolute Address of Function Start relative to overall file (hex)
//
//		Mnemonic Line (inside function):
//			xxxx|xxxx|label|xxxxxxxxxx|xxxxxx|xxxx|DST|SRC|mnemonic|operands
//			  |    |    |        |        |     |   |   |     |        |____  Disassembled operand output (ascii)
//			  |    |    |        |        |     |   |   |     |_____________  Disassembled mnemonic (ascii)
//			  |    |    |        |        |     |   |___|___________________  See below for SRC/DST format
//			  |    |    |        |        |     |___________________________  Addressing/Data bytes from operand portion of instruction (hex)
//			  |    |    |        |        |_________________________________  Opcode bytes from instruction (hex)
//			  |    |    |        |__________________________________________  All bytes from instruction (hex)
//			  |    |    |___________________________________________________  Label(s) for this address (comma separated list)
//			  |    |________________________________________________________  Absolute address of instruction (hex)
//			  |_____________________________________________________________  Relative address of instruction to the function (hex)
//
//		Data Byte Line (inside function):
//			xxxx|xxxx|label|xx
//			  |    |    |    |____  Data Byte (hex)
//			  |    |    |_________  Label(s) for this address (comma separated)
//			  |    |______________  Absolute address of data byte (hex)
//			  |___________________  Relative address of data byte to the function (hex)
//
//		SRC and DST entries:
//			#xxxx			Immediate Data Value (xxxx=hex value)
//			C@xxxx			Absolute Code Address (xxxx=hex address)
//			C^n(xxxx)		Relative Code Address (n=signed offset in hex, xxxx=resolved absolute address in hex)
//			C&xx(r)			Register Code Offset (xx=hex offset, r=register number or name), ex: jmp 2,x -> "C$02(x)"
//			D@xxxx			Absolute Data Address (xxxx=hex address)
//			D^n(xxxx)		Relative Data Address (n=signed offset in hex, xxxx=resolved absolute address in hex)
//			D&xx(r)			Register Data Offset (xx=hex offset, r=register number or name), ex: ldaa 1,y -> "D$01(y)"
//
//			If any of the above also includes a mask, then the following will be added:
//			,Mxx			Value mask (xx=hex mask value)
//
//		Note: The address sizes are consistent with the particular process.  For example, an HC11 will
//			use 16-bit addresses (or 4 hex digits).  The size of immediate data entries, offsets, and masks will
//			reflect the actual value.  A 16-bit immediate value, offset, or mask, will be outputted as 4 hex
//			digits, but an 8-bit immediate value, offset, or mask, will be outputted as only 2 hex digits.
//

#include "m6811gdc.h"
#include "gdc.h"
#include "stringhelp.h"
#include <sstream>
#include <cstdio>

#include <assert.h>

#define DataDelim	"'"			// Specify ' as delimiter for data literals
#define LblcDelim	":"			// Delimiter between labels and code
#define LbleDelim	""			// Delimiter between labels and equates
#define	ComDelimS	";"			// Comment Start delimiter
#define ComDelimE	""			// Comment End delimiter
#define HexDelim	"0x"		// Hex. delimiter

#define VERSION 0x200				// M6811 Disassembler Version number 2.00

// ----------------------------------------------------------------------------
//	CM6811Disassembler
// ----------------------------------------------------------------------------
CM6811Disassembler::CM6811Disassembler()
	: CDisassembler()
{
//                = ((NBytes: 0; OpCode: (0, 0); Grp: 0; Control: 1; Mnemonic: '???'),
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x00", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "test"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x01", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "nop"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x02", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "idiv"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x03", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "fdiv"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x04", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "lsrd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x05", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "lsld"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x06", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tap"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x07", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tpa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x08", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "inx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x09", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "dex"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x0A", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "clv"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x0B", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "sev"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x0C", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "clc"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x0D", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "sec"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x0E", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "cli"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x0F", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "sei"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x10", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "sba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x11", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "cba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x12", MAKEOGRP(0x7, 0x3), MAKEOCTL(0x1, 0x3), "brset"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x13", MAKEOGRP(0x7, 0x3), MAKEOCTL(0x1, 0x3), "brclr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x14", MAKEOGRP(0x0, 0x7), MAKEOCTL(0x0, 0x1), "bset"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x15", MAKEOGRP(0x0, 0x7), MAKEOCTL(0x0, 0x1), "bclr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x16", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x17", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tba"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x08", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "iny"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x09", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "dey"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x1C", MAKEOGRP(0x0, 0x9), MAKEOCTL(0x0, 0x0), "bset"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x1D", MAKEOGRP(0x0, 0x9), MAKEOCTL(0x0, 0x0), "bclr"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x1E", MAKEOGRP(0x9, 0x3), MAKEOCTL(0x0, 0x3), "brset"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x1F", MAKEOGRP(0x9, 0x3), MAKEOCTL(0x0, 0x3), "brclr"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x30", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tsy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x35", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tys"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x38", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "puly"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x3A", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "aby"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x3C", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "pshy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x60", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "neg"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x63", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "com"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x64", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "lsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x66", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "ror"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x67", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "asr"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x68", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "lsl"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x69", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "rol"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x6A", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "dec"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x6C", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "inc"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x6D", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "tst"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x6E", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x2) | OCTL_STOP, "jmp"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x6F", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "clr"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x8C", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "cpy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x8F", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "xgdy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\x9C", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "cpy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA0", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "suba"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA1", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "cmpa"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA2", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "sbca"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA3", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "subd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA4", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "anda"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA5", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "bita"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA6", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "ldaa"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA7", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "staa"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA8", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "eora"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xA9", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "adca"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xAA", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "oraa"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xAB", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "adda"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xAC", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "cpy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xAD", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x2), "jsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xAE", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "lds"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xAF", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "sts"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xBC", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "cpy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xCE", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "ldy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xDE", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "ldy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xDF", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "sty"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE0", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "subb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE1", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "cmpb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE2", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "sbcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE3", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "addd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE4", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "andb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE5", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "bitb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE6", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "ldab"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE7", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "stab"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE8", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "eorb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xE9", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "adcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xEA", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "orab"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xEB", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "addb"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xEC", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "ldd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xED", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "std"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xEE", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "ldy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xEF", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "sty"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xFE", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "ldy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x18\xFF", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "sty"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x19", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "daa"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\x83", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "cpd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\x93", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "cpd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\xA3", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "cpd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\xAC", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "cpy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\xB3", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "cpd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\xEE", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "ldy"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\x1A\xEF", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "sty"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x1B", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "aba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x1C", MAKEOGRP(0x0, 0x8), MAKEOCTL(0x0, 0x0), "bset"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x1D", MAKEOGRP(0x0, 0x8), MAKEOCTL(0x0, 0x0), "bclr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x1E", MAKEOGRP(0x8, 0x3), MAKEOCTL(0x0, 0x3), "brset"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x1F", MAKEOGRP(0x8, 0x3), MAKEOCTL(0x0, 0x3), "brclr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x20", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3) | OCTL_STOP, "bra"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x21", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "brn"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x22", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bhi"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x23", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bls"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x24", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bcc"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x25", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bcs"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x26", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bne"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x27", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "beq"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x28", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bvc"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x29", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bvs"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x2A", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bpl"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x2B", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bmi"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x2C", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bge"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x2D", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "blt"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x2E", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bgt"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x2F", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "ble"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x30", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tsx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x31", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "ins"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x32", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "pula"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x33", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "pulb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x34", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "des"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x35", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "txs"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x36", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "psha"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x37", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "pshb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x38", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "pulx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x39", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0) | OCTL_STOP, "rts"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x3A", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "abx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x3B", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0) | OCTL_STOP, "rti"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x3C", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "pshx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x3D", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "mul"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x3E", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "wai"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x3F", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "swi"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x40", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "nega"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x43", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "coma"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x44", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "lsra"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x46", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "rora"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x47", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "asra"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x48", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "lsla"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x49", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "rola"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x4A", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "deca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x4C", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "inca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x4D", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tsta"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x4F", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "clra"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x50", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "negb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x53", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "comb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x54", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "lsrb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x56", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "rorb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x57", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "asrb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x58", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "lslb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x59", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "rolb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x5A", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "decb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x5C", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "incb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x5D", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "tstb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x5F", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "clrb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x60", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "neg"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x63", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "com"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x64", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "lsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x66", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "ror"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x67", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "asr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x68", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "lsl"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x69", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "rol"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x6A", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "dec"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x6C", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "inc"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x6D", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "tst"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x6E", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x2) | OCTL_STOP, "jmp"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x6F", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "clr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x70", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "neg"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x73", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "com"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x74", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "lsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x76", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "ror"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x77", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "asr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x78", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "lsl"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x79", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "rol"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x7A", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "dec"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x7C", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "inc"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x7D", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "tst"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x7E", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x3) | OCTL_STOP, "jmp"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x7F", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "clr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x80", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "suba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x81", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "cmpa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x82", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "sbca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x83", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "subd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x84", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "anda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x85", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "bita"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x86", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "ldaa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x88", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "eora"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x89", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "adca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x8A", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "oraa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x8B", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "adda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x8C", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "cpx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x8D", MAKEOGRP(0x0, 0x3), MAKEOCTL(0x0, 0x3), "bsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x8E", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "lds"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x8F", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "xgdx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x90", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "suba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x91", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "cmpa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x92", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "sbca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x93", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "subd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x94", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "anda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x95", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "bita"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x96", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "ldaa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x97", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "staa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x98", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "eora"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x99", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "adca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x9A", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "oraa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x9B", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "adda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x9C", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "cpx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x9D", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x3), "jsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x9E", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "lds"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\x9F", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "sts"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA0", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "suba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA1", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "cmpa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA2", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "sbca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA3", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "subd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA4", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "anda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA5", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "bita"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA6", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "ldaa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA7", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "staa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA8", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "eora"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xA9", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "adca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xAA", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "oraa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xAB", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "adda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xAC", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "cpx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xAD", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x2), "jsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xAE", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "lds"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xAF", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "sts"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB0", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "suba"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB1", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "cmpa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB2", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "sbca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB3", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "subd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB4", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "anda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB5", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "bita"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB6", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "ldaa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB7", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "staa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB8", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "eora"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xB9", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "adca"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xBA", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "oraa"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xBB", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "adda"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xBC", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "cpx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xBD", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x3), "jsr"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xBE", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "lds"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xBF", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "sts"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC0", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "subb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC1", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "cmpb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC2", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "sbcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC3", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "addd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC4", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "andb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC5", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "bitb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC6", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "ldab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC8", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "eorb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xC9", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "adcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xCA", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "orab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xCB", MAKEOGRP(0x0, 0x5), MAKEOCTL(0x0, 0x0), "addb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xCC", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "ldd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\xCD\xA3", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "cpd"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\xCD\xAC", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "cpx"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\xCD\xEE", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "ldx"));
	m_Opcodes.AddOpcode(COpcodeEntry(2, (unsigned char *)"\xCD\xEF", MAKEOGRP(0x0, 0xB), MAKEOCTL(0x0, 0x0), "stx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xCE", MAKEOGRP(0x0, 0x6), MAKEOCTL(0x0, 0x0), "ldx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xCF", MAKEOGRP(0x0, 0x0), MAKEOCTL(0x0, 0x0), "stop"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD0", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "subb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD1", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "cmpb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD2", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "sbcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD3", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "addd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD4", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "andb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD5", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "bitb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD6", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "ldab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD7", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "stab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD8", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "eorb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xD9", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "adcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xDA", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "orab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xDB", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "addb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xDC", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "ldd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xDD", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "std"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xDE", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "ldx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xDF", MAKEOGRP(0x0, 0x1), MAKEOCTL(0x0, 0x1), "stx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE0", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "subb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE1", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "cmpb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE2", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "sbcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE3", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "addd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE4", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "andb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE5", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "bitb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE6", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "ldab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE7", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "stab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE8", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "eorb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xE9", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "adcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xEA", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "orab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xEB", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "addb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xEC", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "ldd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xED", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "std"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xEE", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "ldx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xEF", MAKEOGRP(0x0, 0xA), MAKEOCTL(0x0, 0x0), "stx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF0", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "subb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF1", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "cmpb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF2", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "sbcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF3", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "addd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF4", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "andb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF5", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "bitb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF6", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "ldab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF7", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "stab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF8", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "eorb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xF9", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "adcb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xFA", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "orab"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xFB", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "addb"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xFC", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "ldd"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xFD", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "std"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xFE", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "ldx"));
	m_Opcodes.AddOpcode(COpcodeEntry(1, (unsigned char *)"\xFF", MAKEOGRP(0x0, 0x2), MAKEOCTL(0x0, 0x1), "stx"));

	m_Memory = new TMemObject(1, 0x10000ul, 0x00, true);			// 64K of memory available to processor
	m_Memory->AddMapping(0ul, 0, 0ul);								// Mapped as one block

	SectionCount = 0;
	CBDef = true;
}

unsigned int CM6811Disassembler::GetVersionNumber()
{
	return (CDisassembler::GetVersionNumber() | VERSION);			// Get GDC version and append our version to it
}

std::string CM6811Disassembler::GetGDCLongName() {
	return "M6811 Disassembler GDC";
}

std::string CM6811Disassembler::GetGDCShortName() {
	return "M6811GDC";
}

bool CM6811Disassembler::ResolveIndirect(unsigned int nAddress, unsigned int& nResAddress, int nType)
{
	unsigned int	aVector;

	// In the HC11, we can assume that all indirect addresses are 2-bytes in length
	//	and stored in little endian format.
	aVector = 0;
	if ((IsAddressLoaded(nAddress, 2) == false) ||			// Not only must it be loaded, but we must have never examined it before!
		(m_Memory->GetDescriptor(nAddress) != DMEM_LOADED) ||
		(m_Memory->GetDescriptor(nAddress+1) != DMEM_LOADED)) {
		nResAddress = 0;
		return false;
	}
	aVector = m_Memory->GetByte(nAddress) * 256ul + m_Memory->GetByte(nAddress + 1);
	nResAddress = aVector;
	m_Memory->SetDescriptor(nAddress, DMEM_CODEINDIRECT + nType);		// Flag the addresses as being the proper vector type
	m_Memory->SetDescriptor(nAddress+1, DMEM_CODEINDIRECT + nType);
	return true;
}

std::string CM6811Disassembler::GetExcludedPrintChars()
{
	return "\\" DataDelim;
}

std::string CM6811Disassembler::GetHexDelim()
{
	return HexDelim;
}

std::string CM6811Disassembler::GetCommentStartDelim()
{
	return ComDelimS;
}

std::string CM6811Disassembler::GetCommentEndDelim()
{
	return ComDelimE;
}

bool CM6811Disassembler::CompleteObjRead(bool bAddLabels, std::ostream *msgFile, std::ostream *errFile)
{
	// Procedure to finish reading opcode from memory.  This procedure reads operand bytes,
	//	placing them in m_OpMemory.  Plus branch/labels and data/labels are generated (according to function).

	bool A,B;
	char strTemp[10];

	CBDef = true;								// On HC11 all conditionally defined are defined, unlike 6809

	OpPointer = m_OpMemory.size();				// Get position of start of operands following opcode
	StartPC = m_PC - m_OpMemory.size();			// Get PC of first byte of this instruction for branch references

	// Note: We'll start with the absolute address.  Since we don't know what the relative address is
	//		to the start of the function, then the function outputting function (which should know it),
	//		will have to add it in:

	std::sprintf(strTemp, "%04X|", StartPC);
	m_sFunctionalOpcode = strTemp;

	// Move Bytes to m_OpMemory:
	A = MoveOpcodeArgs(OGRP_DST);
	B = MoveOpcodeArgs(OGRP_SRC);
	if ((A == false) || (B == false)) return false;

	TLabelTableMap::const_iterator itrLabel = m_LabelTable.find(StartPC);
	if (itrLabel != m_LabelTable.end()) {
		for (unsigned int i=0; i<itrLabel->second.size(); ++i) {
			if (i != 0) m_sFunctionalOpcode += ",";
			m_sFunctionalOpcode += FormatLabel(LC_REF, itrLabel->second.at(i), StartPC);
		}
	}

	m_sFunctionalOpcode += "|";

	for (unsigned int i=0; i<m_OpMemory.size(); ++i) {
		std::sprintf(strTemp, "%02X", m_OpMemory.at(i));
		m_sFunctionalOpcode += strTemp;
	}

	m_sFunctionalOpcode += "|";

	for (unsigned int i=0; i<OpPointer; ++i) {
		std::sprintf(strTemp, "%02X", m_OpMemory.at(i));
		m_sFunctionalOpcode += strTemp;
	}

	m_sFunctionalOpcode += "|";

	for (unsigned int i=OpPointer; i<m_OpMemory.size(); ++i) {
		std::sprintf(strTemp, "%02X", m_OpMemory.at(i));
		m_sFunctionalOpcode += strTemp;
	}

	m_sFunctionalOpcode += "|";

	// Decode Operands:
	A = DecodeOpcode(OGRP_DST, OCTL_DST, bAddLabels, msgFile, errFile);

	m_sFunctionalOpcode += "|";

	B = DecodeOpcode(OGRP_SRC, OCTL_SRC, bAddLabels, msgFile, errFile);
	if ((A == false) || (B == false)) return false;

	m_sFunctionalOpcode += "|";
	m_sFunctionalOpcode += FormatMnemonic(MC_OPCODE);
	m_sFunctionalOpcode += "|";
	m_sFunctionalOpcode += FormatOperands(MC_OPCODE);

	// See if this is the end of a function.  Note: These preempt all previously
	//		decoded function tags -- such as call, etc:
	if ((compareNoCase(m_CurrentOpcode.m_Mnemonic, "rts") == 0) ||
		(compareNoCase(m_CurrentOpcode.m_Mnemonic, "rti") == 0)) {
		m_FunctionsTable[StartPC] = FUNCF_HARDSTOP;
	}

	return true;
}

bool CM6811Disassembler::RetrieveIndirect(std::ostream * /* msgFile */, std::ostream * /* errFile */)
{
	MEM_DESC b1d, b2d;

	m_OpMemory.clear();
	m_OpMemory.push_back(m_Memory->GetByte(m_PC));
	m_OpMemory.push_back(m_Memory->GetByte(m_PC+1));
	// All HC11 indirects are Motorola format and are 2-bytes in length, regardless:
	b1d = (MEM_DESC)m_Memory->GetDescriptor(m_PC);
	b2d = (MEM_DESC)m_Memory->GetDescriptor(m_PC+1);
	if (((b1d != DMEM_CODEINDIRECT) && (b1d != DMEM_DATAINDIRECT)) ||
		((b2d != DMEM_CODEINDIRECT) && (b2d != DMEM_DATAINDIRECT))) {
		m_PC += 2;
		return false;			// Memory should be tagged as indirect!
	}
	if (b1d != b2d) {
		m_PC += 2;
		return false;			// Memory should be tagged as a correct pair!
	}

	if (((b1d == DMEM_CODEINDIRECT) && (m_CodeIndirectTable.find(m_PC) == m_CodeIndirectTable.end())) ||
		((b1d == DMEM_DATAINDIRECT) && (m_DataIndirectTable.find(m_PC) == m_DataIndirectTable.end()))) {
		m_PC += 2;
		return false;			// Location must exist in one of the two tables!
	}
	m_PC += 2;
	return true;
}


bool CM6811Disassembler::MoveOpcodeArgs(unsigned int nGroup)
{
	switch (nGroup) {
		case 0x2:
		case 0x4:
		case 0x6:
		case 0x7:
		case 0x8:
		case 0x9:
			m_OpMemory.push_back(m_Memory->GetByte(m_PC++));
			// Fall through and do it again:
		case 0x1:
		case 0x3:
		case 0x5:
		case 0xA:
		case 0xB:
			m_OpMemory.push_back(m_Memory->GetByte(m_PC++));
			break;
		case 0x0:
			break;
		default:
			return false;
	}
	return true;
}

bool CM6811Disassembler::DecodeOpcode(unsigned int nGroup, unsigned int nControl, bool bAddLabels, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;

	char strTemp[30];
	char strTemp2[30];
	unsigned int nTargetAddr;

	strTemp[0] = 0;
	nTargetAddr = 0xFFFFFFFF;

	switch (nGroup) {
		case 0x0:								// No operand
			break;
		case 0x1:								// absolute 8-bit, assume msb=$00
			switch (nControl) {
				case 1:
					if (bAddLabels) GenDataLabel(m_OpMemory[OpPointer], StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "D@%02lX", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;
				case 3:
					if (bAddLabels) GenAddrLabel(m_OpMemory[OpPointer], StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "C@%02lX", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					nTargetAddr = static_cast<unsigned long>(m_OpMemory[OpPointer]);
					break;
				default:
					RetVal = false;
			}
			OpPointer++;
			break;
		case 0x2:								// 16-bit Absolute
			switch (nControl) {
				case 1:
					if (bAddLabels) GenDataLabel(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1], StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "D@%04lX", static_cast<unsigned long>(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]));
					break;
				case 3:
					if (bAddLabels) GenAddrLabel(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1], StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "C@%04lX", static_cast<unsigned long>(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]));
					nTargetAddr = static_cast<unsigned long>(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]);
					break;
				default:
					RetVal = false;
			}
			OpPointer += 2;
			break;
		case 0x3:								// 8-bit Relative
			switch (nControl) {
				case 1:
					if (bAddLabels) GenDataLabel(m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]), StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "D^%c%02lX(%04lX)",
											((((signed long)(signed char)(m_OpMemory[OpPointer])) !=
											labs((signed long)(signed char)(m_OpMemory[OpPointer]))) ? '-' : '+'),
											labs((signed long)(signed char)(m_OpMemory[OpPointer])),
											m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]));
					break;
				case 3:
					if (bAddLabels) GenAddrLabel(m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]), StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "C^%c%02lX(%04lX)",
											((((signed long)(signed char)(m_OpMemory[OpPointer])) !=
											labs((signed long)(signed char)(m_OpMemory[OpPointer]))) ? '-' : '+'),
											labs((signed long)(signed char)(m_OpMemory[OpPointer])),
											m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]));
					nTargetAddr = m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]);
					break;
				default:
					RetVal = false;
			}
			OpPointer++;
			break;
		case 0x4:								// 16-bit Relative
			switch (nControl) {
				case 1:
					if (bAddLabels) GenDataLabel(m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]), StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "D^%c%04lX(%04lX)",
											((((signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1])) !=
											labs((signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]))) ? '-' : '+'),
											labs((signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1])),
											m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]));
					break;
				case 3:
					if (bAddLabels) GenAddrLabel(m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]), StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp, "C^%c%04lX(%04lX)",
											((((signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1])) !=
											labs((signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]))) ? '-' : '+'),
											labs((signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1])),
											m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]));
					nTargetAddr = m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]);
					break;
				default:
					RetVal = false;
			}
			OpPointer += 2;
			break;
		case 0x5:								// Immediate 8-bit data -- no label
			std::sprintf(strTemp, "#%02lX", static_cast<unsigned long>(m_OpMemory[OpPointer]));
			OpPointer++;
			break;
		case 0x6:								// Immediate 16-bit data -- no label
			std::sprintf(strTemp, "#%04lX", static_cast<unsigned long>(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]));
			OpPointer += 2;
			break;
		case 0x7:								// 8-bit Absolute address, and mask
			strTemp2[0] = 0;
			switch (nControl) {
				case 1:
					if (bAddLabels) GenDataLabel(m_OpMemory[OpPointer], StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp2, "D@%02lX", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;
				case 3:
					if (bAddLabels) GenAddrLabel(m_OpMemory[OpPointer], StartPC, std::string(), msgFile, errFile);
					std::sprintf(strTemp2, "C@%02lX", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					nTargetAddr = static_cast<unsigned long>(m_OpMemory[OpPointer]);
					break;
				default:
					RetVal = false;
			}
			std::sprintf(strTemp, "%s,M%02lX", strTemp2, static_cast<unsigned long>(m_OpMemory[OpPointer+1]));
			OpPointer += 2;
			break;
		case 0x8:								// 8-bit offset and 8-bit mask (x)
			strTemp2[0] = 0;
			switch (nControl) {
				case 0:
				case 1:
					std::sprintf(strTemp2, "D&%02lX(x)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;

				case 2:
				case 3:
				case 4:
					std::sprintf(strTemp2, "C&%02lX(x)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;
			}
			std::sprintf(strTemp, "%s,M%02lX", strTemp2, static_cast<unsigned long>(m_OpMemory[OpPointer+1]));
			OpPointer += 2;
			break;
		case 0x9:								// 8-bit offset and 8-bit mask (y)
			strTemp2[0] = 0;
			switch (nControl) {
				case 0:
				case 1:
					std::sprintf(strTemp2, "D&%02lX(y)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;

				case 2:
				case 3:
				case 4:
					std::sprintf(strTemp2, "C&%02lX(y)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;
			}
			std::sprintf(strTemp, "%s,M%02lX", strTemp2, static_cast<unsigned long>(m_OpMemory[OpPointer+1]));
			OpPointer += 2;
			break;
		case 0xA:								// 8-bit offset (x)
			switch (nControl) {
				case 0:
				case 1:
					std::sprintf(strTemp, "D&%02lX(x)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;

				case 2:
				case 3:
				case 4:
					std::sprintf(strTemp, "C&%02lX(x)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;
			}
			OpPointer++;
			break;
		case 0xB:								// 8-bit offset (y)
			switch (nControl) {
				case 0:
				case 1:
					std::sprintf(strTemp, "D&%02lX(y)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;

				case 2:
				case 3:
				case 4:
					std::sprintf(strTemp, "C&%02lX(y)", static_cast<unsigned long>(m_OpMemory[OpPointer]));
					break;
			}
			OpPointer++;
			break;
		default:
			RetVal = false;
	}

	m_sFunctionalOpcode += strTemp;

	// See if this is a function branch reference that needs to be added:
	if (nTargetAddr != 0xFFFFFFFF) {
		if ((compareNoCase(m_CurrentOpcode.m_Mnemonic, "jsr") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bsr") == 0)) {
			// Add these only if it is replacing a lower priority value:
			TAddressMap::const_iterator itrFunction = m_FunctionsTable.find(nTargetAddr);
			if (itrFunction == m_FunctionsTable.end()) {
				m_FunctionsTable[nTargetAddr] = FUNCF_CALL;
			} else {
				if (itrFunction->second > FUNCF_CALL) m_FunctionsTable[nTargetAddr] = FUNCF_CALL;
			}

			// See if this is the end of a function:
			if (m_FuncExitAddresses.find(nTargetAddr) != m_FuncExitAddresses.end()) {
				m_FunctionsTable[StartPC] = FUNCF_EXITBRANCH;
			}
		}

		if ((compareNoCase(m_CurrentOpcode.m_Mnemonic, "brset") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "brclr") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "brn") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bhi") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bls") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bcc") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bcs") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bne") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "beq") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bvc") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bvs") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bpl") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bmi") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bge") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "blt") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bgt") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "ble") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bra") == 0) ||
			(compareNoCase(m_CurrentOpcode.m_Mnemonic, "jmp") == 0)) {
			// Add these only if there isn't a function tag here:
			if (m_FunctionsTable.find(nTargetAddr) == m_FunctionsTable.end()) m_FunctionsTable[nTargetAddr] = FUNCF_BRANCHIN;
		}
	}

	// See if this is the end of a function:
	if ((compareNoCase(m_CurrentOpcode.m_Mnemonic, "jmp") == 0) ||
		(compareNoCase(m_CurrentOpcode.m_Mnemonic, "bra") == 0)) {
		if (nTargetAddr != 0xFFFFFFFF) {
			if (m_FuncExitAddresses.find(nTargetAddr) != m_FuncExitAddresses.end()) {
				m_FunctionsTable[StartPC] = FUNCF_EXITBRANCH;
			} else {
				m_FunctionsTable[StartPC] = FUNCF_BRANCHOUT;
			}
		} else {
			// Non-Deterministic branches get tagged as a branchout:
			//m_FunctionsTable[StartPC] = FUNCF_BRANCHOUT;

			// Non-Deterministic branches get tagged as a hardstop (usually it exits the function):
			m_FunctionsTable[StartPC] = FUNCF_HARDSTOP;
		}
	}

	return RetVal;
}

void CM6811Disassembler::CreateOperand(unsigned int nGroup, std::string& sOpStr)
{
	char strTemp[30];

	switch (nGroup) {
		case 0x1:								// absolute 8-bit, assume msb=$00
			sOpStr += "*";
			sOpStr += LabelDeref2(m_OpMemory[OpPointer]);
			OpPointer++;
			break;
		case 0x2:								// 16-bit Absolute
			sOpStr += LabelDeref4(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]);
			OpPointer += 2;
			break;
		case 0x3:								// 8-bit Relative
			sOpStr += LabelDeref4(m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]));
			OpPointer++;
			break;
		case 0x4:								// 16-bit Relative
			sOpStr += LabelDeref4(m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]));
			OpPointer += 2;
			break;
		case 0x5:								// Immediate 8-bit data
			std::sprintf(strTemp, "#%s%02X", GetHexDelim().c_str(), m_OpMemory[OpPointer]);
			sOpStr += strTemp;
			OpPointer++;
			break;
		case 0x6:								// Immediate 16-bit data
			std::sprintf(strTemp, "#%s%04X", GetHexDelim().c_str(), m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]);
			sOpStr += strTemp;
			OpPointer += 2;
			break;
		case 0x7:								// 8-bit Absolute address, and mask
			sOpStr += "*";
			sOpStr += LabelDeref2(m_OpMemory[OpPointer]);
			sOpStr += ",";
			std::sprintf(strTemp, "#%s%02X", GetHexDelim().c_str(), m_OpMemory[OpPointer+1]);
			sOpStr += strTemp;
			OpPointer += 2;
			break;
		case 0x8:								// 8-bit offset and 8-bit mask (x)
			std::sprintf(strTemp, "%s%02X,x,#%s%02X", GetHexDelim().c_str(), m_OpMemory[OpPointer],
													  GetHexDelim().c_str(), m_OpMemory[OpPointer+1]);
			sOpStr += strTemp;
			OpPointer += 2;
			break;
		case 0x9:								// 8-bit offset and 8-bit mask (y)
			std::sprintf(strTemp, "%s%02X,y,#%s%02X", GetHexDelim().c_str(), m_OpMemory[OpPointer],
													  GetHexDelim().c_str(), m_OpMemory[OpPointer+1]);
			sOpStr += strTemp;
			OpPointer += 2;
			break;
		case 0xA:								// 8-bit offset (x)
			std::sprintf(strTemp, "%s%02X,x", GetHexDelim().c_str(), m_OpMemory[OpPointer]);
			sOpStr += strTemp;
			OpPointer++;
			break;
		case 0xB:								// 8-bit offset (y)
			std::sprintf(strTemp, "%s%02X,y", GetHexDelim().c_str(), m_OpMemory[OpPointer]);
			sOpStr += strTemp;
			OpPointer++;
			break;
	}
}

bool CM6811Disassembler::CheckBranchOutside(unsigned int nGroup)
{
	bool RetVal = true;
	unsigned int Address;

	switch (nGroup) {
		case 0x1:								// absolute 8-bit, assume msb=$00
			Address = m_OpMemory[OpPointer];
			RetVal = IsAddressLoaded(Address, 1);
			OpPointer++;
			break;
		case 0x2:								// 16-bit Absolute
			Address = m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1];
			RetVal = IsAddressLoaded(Address, 1);
			OpPointer += 2;
			break;
		case 0x3:								// 8-bit Relative
			Address = m_PC+(signed long)(signed char)(m_OpMemory[OpPointer]);
			RetVal = IsAddressLoaded(Address, 1);
			OpPointer++;
			break;
		case 0x4:								// 16-bit Relative
			Address = m_PC+(signed long)(signed short)(m_OpMemory[OpPointer]*256+m_OpMemory[OpPointer+1]);
			RetVal = IsAddressLoaded(Address, 1);
			OpPointer += 2;
			break;
	}
	return RetVal;
}

std::string CM6811Disassembler::FormatLabel(LABEL_CODE nLC, const std::string & szLabel, unsigned int nAddress)
{
	std::string Temp = CDisassembler::FormatLabel(nLC, szLabel, nAddress);	// Call parent

	switch (nLC) {
		case LC_EQUATE:
			Temp += LbleDelim;
			break;
		case LC_DATA:
		case LC_CODE:
			Temp += LblcDelim;
			break;
		default:
			break;
	}
	return Temp;
}


std::string CM6811Disassembler::FormatMnemonic(MNEMONIC_CODE nMCCode)
{
	switch (nMCCode) {
		case MC_OPCODE:
			return m_CurrentOpcode.m_Mnemonic;
		case MC_ILLOP:
			return "???";
		case MC_EQUATE:
			return "=";
		case MC_DATABYTE:
			return ".byte";
		case MC_ASCII:
			return ".ascii";
		case MC_INDIRECT:
			return ".word";
	}
	return "???";
}

std::string CM6811Disassembler::FormatOperands(MNEMONIC_CODE nMCCode)
{
	std::string OpStr;
	char strTemp[30];
	unsigned int Address;

	OpStr = "";
	switch (nMCCode) {
		case MC_ILLOP:
		case MC_DATABYTE:
			for (unsigned int i=0; i<m_OpMemory.size(); ++i) {
				std::sprintf(strTemp, "%s%02X", GetHexDelim().c_str(), m_OpMemory.at(i));
				OpStr += strTemp;
				if (i < (m_OpMemory.size()-1)) OpStr += ",";
			}
			break;
		case MC_ASCII:
			OpStr += DataDelim;
			for (unsigned int i=0; i<m_OpMemory.size(); ++i) {
				std::sprintf(strTemp, "%c", m_OpMemory.at(i));
				OpStr += strTemp;
			}
			OpStr += DataDelim;
			break;
		case MC_EQUATE:
			std::sprintf(strTemp, "%s%04X", GetHexDelim().c_str(), m_PC);
			OpStr = strTemp;
			break;
		case MC_INDIRECT:
		{
			if (m_OpMemory.size() != 2) {
				assert(false);			// Check code and make sure RetrieveIndirect got called and called correctly!
				break;
			}
			Address = m_OpMemory.at(0)*256+m_OpMemory.at(1);
			std::string strLabel;
			TAddressLabelMap::const_iterator itrLabel;
			if ((itrLabel = m_CodeIndirectTable.find(m_PC-2)) != m_CodeIndirectTable.end()) {
				strLabel = itrLabel->second;
			} else if ((itrLabel = m_DataIndirectTable.find(m_PC-2)) != m_DataIndirectTable.end()) {
				strLabel = itrLabel->second;
			}
			OpStr = FormatLabel(LC_REF, strLabel, Address);
			break;
		}
		case MC_OPCODE:
			OpPointer = m_CurrentOpcode.m_OpcodeBytes.size();	// Get position of start of operands following opcode
			StartPC = m_PC - m_OpMemory.size();			// Get PC of first byte of this instruction for branch references

			CreateOperand(OGRP_DST, OpStr);				// Handle Destination operand first
			if (OGRP_DST != 0x0) OpStr += ",";
			CreateOperand(OGRP_SRC, OpStr);				// Handle Source operand last
			break;
	}

	return OpStr;
}

std::string CM6811Disassembler::FormatComments(MNEMONIC_CODE nMCCode)
{
	std::string RetVal;
	bool Flag;
	unsigned int Address;

	RetVal = "";

	// Handle Undetermined Branch:
	switch (nMCCode) {
		case MC_OPCODE:
			if ((OCTL_SRC == 0x2) || (OCTL_DST == 0x2) ||
				((CBDef == false) && ((OCTL_SRC == 0x4) || (OCTL_DST == 0x4)))) {
				RetVal = "Undetermined Branch Address";
			}
			break;
		default:
			break;
	}

	// Handle out-of-source branch:
	Flag = false;
	switch (nMCCode) {
		case MC_OPCODE:
			OpPointer = m_CurrentOpcode.m_OpcodeBytes.size();	// Get position of start of operands following opcode
			StartPC = m_PC - m_OpMemory.size();		// Get PC of first byte of this instruction for branch references
			switch (OCTL_DST) {
				case 0x2:
				case 0x3:
				case 0x4:
					if (CheckBranchOutside(OGRP_DST) == false) Flag = true;
					break;
			}
			switch (OCTL_SRC) {
				case 0x2:
				case 0x3:
				case 0x4:
					if (CheckBranchOutside(OGRP_SRC) == false) Flag = true;
					break;
			}
			break;
		case MC_INDIRECT:
			Address = m_OpMemory.at(0)*256+m_OpMemory.at(1);
			if (m_CodeIndirectTable.find(m_PC-2) != m_CodeIndirectTable.end()) {
				if (IsAddressLoaded(Address, 1) == false) Flag = true;
			}
			break;
		default:
			break;
	}

	if (Flag) {
		if (!RetVal.empty()) RetVal += ", ";
		RetVal += "Branch Outside Loaded Source(s)";
	}

	// Add general refernce stuff:
	if (!RetVal.empty()) RetVal += "\t";
	RetVal += CDisassembler::FormatComments(nMCCode);		// Call parent and add default comments... i.e references
	return RetVal;
}


bool CM6811Disassembler::WritePreSection(std::ostream& outFile, std::ostream * /* msgFile */, std::ostream * /* errFile */)
{
	TStringArray OutLine;
	char strTemp[30];

	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(m_PC);
	OutLine[FC_MNEMONIC] = ".area";
	std::sprintf(strTemp, "CODE%d\t(ABS)", ++SectionCount);
	OutLine[FC_OPERANDS] = strTemp;
	outFile << MakeOutputLine(OutLine) << "\n";

	OutLine[FC_MNEMONIC] = ".org";
	std::sprintf(strTemp, "%s%04X", GetHexDelim().c_str(), m_PC);
	OutLine[FC_OPERANDS] = strTemp;
	outFile << MakeOutputLine(OutLine) << "\n";

	OutLine[FC_MNEMONIC] = "";
	OutLine[FC_OPERANDS] = "";
	outFile << MakeOutputLine(OutLine) << "\n";
	return true;
}

std::string CM6811Disassembler::LabelDeref2(unsigned int nAddress)
{
	std::string strTemp;
	char strCharTemp[30];

	TLabelTableMap::const_iterator itrLabel = m_LabelTable.find(nAddress);
	if (itrLabel != m_LabelTable.end()) {
		if (itrLabel->second.size()) {
			strTemp = FormatLabel(LC_REF, itrLabel->second.at(0), nAddress);
		} else {
			strTemp = FormatLabel(LC_REF, std::string(), nAddress);
		}
	} else {
		std::sprintf(strCharTemp, "%s%02X", GetHexDelim().c_str(), nAddress);
		strTemp = strCharTemp;
	}
	return strTemp;
}

std::string CM6811Disassembler::LabelDeref4(unsigned int nAddress)
{
	std::string strTemp;
	char strCharTemp[30];

	TLabelTableMap::const_iterator itrLabel = m_LabelTable.find(nAddress);
	if (itrLabel != m_LabelTable.end()) {
		if (itrLabel->second.size()) {
			strTemp = FormatLabel(LC_REF, itrLabel->second.at(0), nAddress);
		} else {
			strTemp = FormatLabel(LC_REF, std::string(), nAddress);
		}
	} else {
		std::sprintf(strCharTemp, "%s%04X", GetHexDelim().c_str(), nAddress);
		strTemp = strCharTemp;
	}
	return strTemp;
}
<file_sep>/programs/funcanal/funccomp.cpp
// funccomp.cpp: implementation of the Fuzzy Function Comparison Logic
//
// $Log: funccomp.cpp,v $
// Revision 1.2  2003/09/13 05:39:49  dewhisna
// Added output options and returning of match percentage to function diff.
//
// Revision 1.1  2003/02/09 06:59:29  dewhisna
// Initial Revision - Split comparison logic from Function File I/O
//
//

//
//	The Edit Script is defined as follows:
//
//		During comparison an optimal edit script is calculated and is stored as a CStringArray.  Each
//			entry is a string of the following format, which is similar to the Diff format except
//			that each entry is unique rather than specifying ranges:
//				xxxCyyy
//
//					Where:
//						xxx = Left side index
//						yyy = Right side index
//						C is one of the following symbols:
//							'>' - Delete xxx from left at point yyy in right or
//									insert xxx from left at point yyy in right
//							'-' - Replace xxx in left with yyyy in right
//							'<' - Insert yyy from right at left point xxx or
//									delete yyy from right at point xxx in left
//

#include "stdafx.h"
#include "funcdesc.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

static CStringArray m_EditScript;
static BOOL m_bEditScriptValid = FALSE;


double CompareFunctions(FUNC_COMPARE_METHOD nMethod,
											CFuncDescFile *pFile1, int nFile1FuncNdx,
											CFuncDescFile *pFile2, int nFile2FuncNdx,
											BOOL bBuildEditScript)
{
	CFuncDesc *pFunction1;
	CFuncDesc *pFunction2;
	CStringArray zFunc1;
	CStringArray zFunc2;
	double nRetVal = 0;
	CString strTemp;

	m_bEditScriptValid = FALSE;
	m_EditScript.RemoveAll();

	if ((pFile1 == NULL) || (pFile2 == NULL)) return nRetVal;

	pFunction1 = pFile1->GetFunc(nFile1FuncNdx);
	pFunction2 = pFile2->GetFunc(nFile2FuncNdx);
	if ((pFunction1 == NULL) ||
		(pFunction2 == NULL)) return nRetVal;

	pFunction1->ExportToDiff(zFunc1);
	pFunction2->ExportToDiff(zFunc2);
	if ((zFunc1.GetSize() == 0) ||
		(zFunc2.GetSize() == 0)) return nRetVal;

	if ((bBuildEditScript) && (nMethod == FCM_DYNPROG_XDROP)) {
		// Note: XDROP Method currently doesn't support building
		//		of edit scripts, so if caller wants to build an
		//		edit script and has selected this method, replace
		//		it with the next best method that does support
		//		edit scripts:
		nMethod = FCM_DYNPROG_GREEDY;
	}

	switch (nMethod) {
		case FCM_DYNPROG_XDROP:
		{
			//
			//	The following algorithm comes from the following source:
			//			"A Greedy Algorithm for Aligning DNA Sequences"
			//			<NAME>, <NAME>, <NAME>, and <NAME>
			//			Journal of Computational Biology
			//			Volume 7, Numbers 1/2, 2000
			//			<NAME>, Inc.
			//			Pp. 203-214
			//
			//			p. 205 : Figure 2 : "A dynamic-programming X-drop algorithm"
			//
			//		T' <- T <- S(0,0) <- 0
			//		k <- L <- U <- 0
			//		repeat {
			//			k <- k + 1
			//			for i <- ceiling(L) to floor(U)+1 in steps of 1/2 do {
			//				j <- k - i
			//				if i is an integer then {
			//					S(i, j) <- Max of:
			//								S(i-1/2, j-1/2) + mat/2		if L <= i-1/2 <= U and a(i) = b(j)
			//								S(i-1/2, j-1/2) + mis/2		if L <= i-1/2 <= U and a(i) != b(j)
			//								S(i, j-1) + ind				if i <= U
			//								S(i-1, j) + ind				if L <= i-1
			//				} else {
			//					S(i, j) <- S(i-1/2, j-1/2)
			//								+ mat/2	if a(i+1/2) = b(j+1/2)
			//								+ mis/2	if a(i+1/2) != b(j+1/2)
			//				}
			//				T' <- max{T', S(i, j)}
			//				if S(i, j) < (T - X) then S(i, j) <- -oo
			//			}
			//			L <- min{i : S(i, k-i) > -oo }
			//			U <- max{i : S(i, k-i) > -oo }
			//			L <- max{L, k+1-N}				<<< Should be: L <- max{L, k+1/2-N}
			//			U <- min{U, M-1}				<<< Should be: U <- min(U, M-1/2}
			//			T <- T'
			//		} until L > U+1
			//		report T'
			//
			//	Given:
			//		arrays: a(1..M), b(1..N) containing the two strings to compare
			//		mat : >0 : Weighting of a match
			//		mis : <0 : Weighting of a mismatch
			//		ind : <0 : Weighting of an insertion/deletion
			//		X = Clipping level : If scoring falls more than X below the
			//				best computed score thus far, then we don't consider
			//				additional extensions for that alignment.  Should
			//				be >= 0 or -1 for infinity.
			//
			//	Returning:
			//		T' = Composite similarity score
			//
			//	For programmatic efficiency, all S indexes have been changed from
			//		0, 1/2 to even/odd and the i loop runs as integers of even/odd
			//		instead of 1/2 increments:
			//
			//	Testing has also been done and it has been proven that the order of
			//		the two arrays has no effect on the outcome.
			//
			//	In the following, we will define oo as DBL_MAX and -oo as -DBL_MAX.
			//
			//	To hold to the non-Generalized Greedy Algorithm requirements, set
			//		ind = mis - mat/2
			//

			CStringArray &a = zFunc1;
			CStringArray &b = zFunc2;
			double Tp, T;
			double **S;
			int i, j, k, L, U;
			double nTemp;
			int M = a.GetSize();
			int N = b.GetSize();
			const double mat = 2;
			const double mis = -2;
			const double ind = -3;
			const double X = -1;

			// Allocate Memory:
			S = new double*[((M+1)*2)];
			if (S == NULL) {
				AfxThrowMemoryException();
				return nRetVal;
			}
			for (i=0; i<((M+1)*2); i++) {
				S[i] = new double[((N+1)*2)];
				if (S[i] == NULL) AfxThrowMemoryException();
			}

			// Initialize:
			for (i=0; i<((M+1)*2); i++) {
				for (j=0; j<((N+1)*2); j++) {
					S[i][j] = -DBL_MAX;
				}
			}

			// Algorithm:
			Tp = T = S[0][0] = 0;
			k = L = U = 0;

			do {
				k = k + 2;
				for (i = L+((L & 0x1) ? 1 : 0); i <= (U - ((U & 0x1) ? 1 : 0) + 2); i++) {
					j = k - i;
					ASSERT(i >= 0);
					ASSERT(i < ((M+1)*2));
					ASSERT(j >= 0);
					ASSERT(j < ((N+1)*2));
					if ((i&1) == 0) {
						nTemp = -DBL_MAX;
						if ((L <= (i-1)) &&
							((i-1) <= U)) {
							// TODO : Improve A/B Comparison:
							if (a.GetAt((i/2)-1).CompareNoCase(b.GetAt((j/2)-1)) == 0) {
								nTemp = __max(nTemp, S[i-1][j-1] + mat/2);
							} else {
								nTemp = __max(nTemp, S[i-1][j-1] + mis/2);
							}
						}
						if (i <= U) {
							nTemp = __max(nTemp, S[i][j-2] + ind);
						}
						if (L <= (i-2)) {
							nTemp = __max(nTemp, S[i-2][j] + ind);
						}
						S[i][j] = nTemp;
					} else {
						// TODO : Improve A/B Comparison:
						if (a.GetAt(((i+1)/2)-1).CompareNoCase(b.GetAt(((j+1)/2)-1)) == 0) {
							S[i][j] = S[i-1][j-1] + mat/2;
						} else {
							S[i][j] = S[i-1][j-1] + mis/2;
						}
					}
					Tp = __max(Tp, S[i][j]);
					if ((X>=0) && (S[i][j] < (T-X))) S[i][j] = -DBL_MAX;
				}

				for (L = 0; L < ((M+1)*2); L++) {
					if ((k - L) < 0) continue;
					if ((k - L) >= ((N+1)*2)) continue;
					if (S[L][k-L] > -DBL_MAX) break;
				}
				if (L == ((M+1)*2)) L=INT_MAX;

				for (U=((M+1)*2)-1; U>=0; U--) {
					if ((k - U) < 0) continue;
					if ((k - U) >= ((N+1)*2)) continue;
					if (S[U][k-U] > -DBL_MAX) break;
				}
				if (U == -1) U=INT_MIN;

				L = __max(L, k + 1 - (N*2));
				U = __min(U, (M*2) - 1);
				T = Tp;
			} while (L <= U+2);

			// If the two PrimaryLabels at the function's address don't match, decrement match by 1*mat.
			//		This helps if there are two are more functions that the user has labeled that
			//		are identical except for the labels:
			if (pFile1->GetPrimaryLabel(pFunction1->GetMainAddress()).CompareNoCase(
					pFile2->GetPrimaryLabel(pFunction2->GetMainAddress())) != 0) Tp = __max(0, Tp - mat);

			// Normalize it:
			nRetVal = Tp/(__max(M,N)*mat);

			// Deallocate Memory:
			for (i=0; i<((M+1)*2); i++) delete[] (S[i]);
			delete[] S;
		}
		break;

		case FCM_DYNPROG_GREEDY:
		{
			//
			//	The following algorithm comes from the following source:
			//			"A Greedy Algorithm for Aligning DNA Sequences"
			//			<NAME>, <NAME>, <NAME>, and <NAME>
			//			Journal of Computational Biology
			//			Volume 7, Numbers 1/2, 2000
			//			<NAME>, Inc.
			//			Pp. 203-214
			//
			//			p. 209 : Figure 4 : "Greedy algorithm that is equivalent to the algorithm
			//								of Figure 2 if ind = mis - mat/2."
			//
			//		i <- 0
			//		while i < min{M, N} and a(i+1) = b(i+1) do i <- i + 1
			//		R(0, 0) <- i
			//		T' <- T[0] <- S'(i+i, 0)
			//		d <- L <- U <- 0
			//		repeat
			//			d <- d + 1
			//			d' <- d - floor( (X + mat/2)/(mat - mis) ) - 1
			//			for k <- L - 1 to U + 1 do
			//				i <- max of:
			//							R(d-1, k-1) + 1		if L < k
			//							R(d-1, k) + 1		if L <= k <= U
			//							R(d-1, k+1)			if k < U
			//				j <- i - k
			//				if i > -oo and S'(i+j, d) >= T[d'] - X then
			//					while i<M, j<N, and a(i+1) = b(j+1) do
			//						i <- i + 1;  j <- j + 1
			//					R(d, k) <- i
			//					T' <- max{T', S'(i+j, d)}
			//				else R(d, k) <- -oo
			//			T[d] <- T'
			//			L <- min{k : R(d, k) > -oo}
			//			U <- max{k : R(d, k) > -oo}
			//			L <- max{L, max{k : R(d, k) = N + k} + 2}	<<< Should be: L <- max{L, max{k : R(d, k) = N + k} + 1}
			//			U <- min{U, min{k : R(d, k) = M } - 2}		<<< Should be: U <- min{U, min{k : R(d, k) = M } - 1}
			//		until L > U + 2
			//		report T'
			//
			//	Given:
			//		arrays: a(1..M), b(1..N) containing the two strings to compare
			//		mat : >0 : Weighting of a match
			//		mis : <0 : Weighting of a mismatch
			//		ind : <0 : Weighting of an insertion/deletion
			//		(Satisfying: ind = mis - mat/2)
			//		X = Clipping level : If scoring falls more than X below the
			//				best computed score thus far, then we don't consider
			//				additional extensions for that alignment.  Should
			//				be >= 0 or -1 for infinity.
			//		S'(i+j, d) = (i+j)*mat/2 - d*(mat-mis)
			//		or S'(k, d) = k*mat/2 - d*(mat-mis)
			//
			//	Returning:
			//		T' = Composite similarity score
			//
			//	Testing has also been done and it has been proven that the order of
			//		the two arrays has no effect on the outcome.
			//
			//	In the following it will be assumed that the number of mismatches
			//	(i.e. array bounds) can't exceed M+N since the absolute maximum
			//	edit script to go from an array of M objects to an array of N
			//	objects is to perform M deletions and N insertions.  However,
			//	these differences can be tracked either forward or backward, so
			//	the memory will be allocated for the full search field.
			//
			//	We are also going to define -oo as being -2 since no index can be
			//	lower than 0.  The reason for the -2 instead of -1 is to allow
			//	for the i=R(d,k)+1 calculations to still be below 0.  That is
			//	to say so that -oo + 1 = -oo
			//

			CStringArray &a = zFunc1;
			CStringArray &b = zFunc2;
			double Tp;				// T' = Overall max for entire comparison
			double Tpp;				// T'' = Overall max for current d value
			double *T;
			double nTemp;
			int **Rm;
			int *Rvisitmin;			// Minimum k-index of R visited for a particular d (for speed)
			int *Rvisitmax;			// Maximum k-index of R visited for a particular k (for speed)
			int i, j, k, L, U;
			int d, dp;
			int dbest, kbest;
			int M = a.GetSize();
			int N = b.GetSize();
			const int dmax = ((M+N)*2)+1;
			const int kmax = (M+N+1);
			const int rksize = (kmax*2)+1;
			const double mat = 2;
			const double mis = -2;
			const double X = -1;
			const int floored_d_offset = (int)((X+(mat/2))/(mat-mis));
			#define Sp(x, y) ((double)((x)*(mat/2) - ((y)*(mat-mis))))
			#define R(x, y) (Rm[(x)][(y)+kmax])

			// Allocate Memory:
			T = new double[dmax];
			if (T == NULL) {
				AfxThrowMemoryException();
				return nRetVal;
			}

			Rvisitmin = new int[dmax];
			if (Rvisitmin == NULL) {
				AfxThrowMemoryException();
				delete T;
				return nRetVal;
			}

			Rvisitmax = new int[dmax];
			if (Rvisitmax == NULL) {
				AfxThrowMemoryException();
				delete T;
				delete Rvisitmin;
				return nRetVal;
			}

			Rm = new int*[dmax];
			if (Rm == NULL) {
				AfxThrowMemoryException();
				delete T;
				delete Rvisitmin;
				delete Rvisitmax;
				return nRetVal;
			}
			for (i=0; i<dmax; i++) {
				Rm[i] = new int[rksize];
				if (Rm[i] == NULL) AfxThrowMemoryException();
			}

			// Initialize:
			for (i=0; i<dmax; i++) {
				T[i] = 0;
				Rvisitmin[i] = kmax+1;
				Rvisitmax[i] = -kmax-1;
				for (j=0; j<rksize; j++) {
					Rm[i][j] = -2;
				}
			}

			// Algorithm:
			i=0;
			// TODO : Improve A/B Comparison:
			while ((i<__min(M, N)) && (a.GetAt(i).CompareNoCase(b.GetAt(i)) == 0)) i++;
			R(0, 0) = i;
			dbest = kbest = 0;
			Tp = T[0] = Sp(i+i, 0);
			d = L = U = 0;
			Rvisitmin[0] = 0;
			Rvisitmax[0] = 0;

/*
printf("\n");
*/

			if ((i != M) || (i != N)) {
				do {
					d++;
					dp = d - floored_d_offset - 1;
					Tpp = -DBL_MAX;
					for (k=(L-1); k<=(U+1); k++) {
						ASSERT(d > 0);
						ASSERT(d < dmax);
						ASSERT(abs(k) <= kmax);
						i = -2;
						if (L < k)			i = __max(i, R(d-1, k-1)+1);
						if ((L <= k) &&
							(k <= U))		i = __max(i, R(d-1, k)+1);
						if (k < U)			i = __max(i, R(d-1, k+1));
						j = i - k;
						if ((i >= 0) && (j >= 0) && ((X<0) || (Sp(i+j, d) >= (((dp >= 0) ? T[dp] : 0) - X)))) {
							// TODO : Improve A/B Comparison:
							while ((i<M) && (j<N) && (a.GetAt(i).CompareNoCase(b.GetAt(j)) == 0)) {
								i++; j++;
							}

							R(d, k) = i;
							if (Rvisitmin[d] > k) Rvisitmin[d] = k;
							if (Rvisitmax[d] < k) Rvisitmax[d] = k;
							nTemp = Sp(i+j, d);
							Tp = __max(Tp, nTemp);
/*
printf("d=%2ld : k=%2ld, i=%2ld, j=%2ld, M=%2ld, N=%2ld, T=%2ld, Tp=%2ld, Tpp=%2ld", d, k, i, j, M, N, (int)nTemp, (int)Tp, (int)Tpp);
*/
							if (nTemp > Tpp) {
								Tpp = nTemp;
/*
printf(" * Best (%2ld)", (int)Tpp);
*/
									dbest = d;
									kbest = k;


									// Account for hitting the max M or N boundaries:
									if ((i != M) || (j != N)) {
										if (j > N) {
											kbest++;
/*
printf(" >>>>>>  k++ j shift");
*/
										} else {
											if (i > M) {
												kbest--;
/*
printf(" <<<<<<  k-- i shift");
*/
											}
										}
									}

							}
/*
printf("\n");
*/

						} else {
							R(d, k) = -2;
							if (Rvisitmin[d] == k) Rvisitmin[d]++;
							if (Rvisitmax[d] >= k) Rvisitmax[d] = k-1;
						}
					}
					T[d] = Tp;

					L = Rvisitmin[d];
					U = Rvisitmax[d];
					for (k=Rvisitmax[d]; k>=Rvisitmin[d]; k--) if (R(d, k) == (N+k)) break;
					if (k<Rvisitmin[d]) k = INT_MIN;
					L = __max(L, k+1);
					for (k=Rvisitmin[d]; k<=Rvisitmax[d]; k++) if (R(d, k) == M) break;
					if (k>Rvisitmax[d]) k = INT_MAX;
					U = __min(U, k-1);
				} while (L <= U+2);
			}

			// If the two PrimaryLabels at the function's address don't match, decrement match by 1*mat.
			//		This helps if there are two are more functions that the user has labeled that
			//		are identical except for the labels:
			if (pFile1->GetPrimaryLabel(pFunction1->GetMainAddress()).CompareNoCase(
					pFile2->GetPrimaryLabel(pFunction2->GetMainAddress())) != 0) Tp = __max(0, Tp - mat);

			// Normalize it:
			nRetVal = Tp/(__max(M,N)*mat);

			// Build Edit Script:
			if (bBuildEditScript) {
				int last_i, last_j;
				int cur_i, cur_j;
				int k_rest;

				if (dbest > 0) {
					m_EditScript.SetSize(dbest);
					k = kbest;
					last_i = M+1;
					last_j = N+1;

/*
printf("\n%s with %s:\n", LPCTSTR(pFunction1->GetMainName()), LPCTSTR(pFunction2->GetMainName()));
*/

					for (d=dbest-1; d>=0; d--) {
						i = __max((R(d, k-1) + 1), __max((R(d, k) + 1), (R(d, k+1))));

/*
printf("(%3ld, %3ld) : %3ld(%5ld), %3ld(%5ld), %3ld(%5ld) :", d, k,
						(R(d, k-1) + 1), (int)Sp((R(d, k-1))*2-k+1, d),
						(R(d, k) + 1), (int)Sp((R(d, k))*2-k, d),
						(R(d, k+1)), (int)Sp((R(d, k+1))*2-k-1, d));

for (j=Rvisitmin[dbest-1]; j<=Rvisitmax[dbest-1]; j++) {
	if (j == k-1) printf("("); else printf(" ");
	if (R(d,j)<0) printf("   "); else printf("%3ld", R(d, j));
	if (j == k+1) printf(")"); else printf(" ");
}
printf("\n");
*/

						j = i-k;

						if (i == (R(d, k-1) + 1)) {
							strTemp.Format("%ld>%ld", i-1, j);
							cur_i = i-1;
							cur_j = j;
							k--;
							k_rest = 1;
						} else {
							if (i == (R(d, k+1))) {
								strTemp.Format("%ld<%ld", i, j-1);
								cur_i = i;
								cur_j = j-1;
								k++;
								k_rest = -1;
							} else {
								// if (i == (R(d, k) + 1))
								strTemp.Format("%ld-%ld", i-1, j-1);
								cur_i = i-1;
								cur_j = j-1;
								// k=k;
								k_rest = 0;
							}
						}
						m_EditScript.SetAt(d, strTemp);
						// The following test is needed since our insertion/deletion indexes are
						//		one greater than the stored i and/or j values from the R matrix.
						//		It is possible that the previous comparison added some extra
						//		entries to the R matrix than what was really needed.  This will
						//		cause extra erroneous entries to appear in the edit script.
						//		However, since the indexes should be always increasing, we simply
						//		filter out extra entries added to the end that don't satisfy
						//		this condition:
						if ((k_rest == 0) &&
							((cur_i == last_i) && (cur_j == last_j))) {
							m_EditScript.RemoveAt(d);
						}

						last_i = cur_i;
						last_j = cur_j;
					}
				}


				// Note: if the two are identical, array stays empty:
				m_bEditScriptValid = TRUE;
			}

			// Deallocate Memory:
			delete[] T;
			delete[] Rvisitmin;
			delete[] Rvisitmax;
			for (i=0; i<dmax; i++) delete[] (Rm[i]);
			delete[] Rm;
		}
		break;
	}

	return nRetVal;
}

BOOL GetLastEditScript(CStringArray &anArray)
{
	int i;

	anArray.RemoveAll();
	if (!m_bEditScriptValid) return FALSE;

	anArray.SetSize(m_EditScript.GetSize());
	for (i=0; i<m_EditScript.GetSize(); i++) anArray.SetAt(i, m_EditScript.GetAt(i));

	return TRUE;
}

CString DiffFunctions(FUNC_COMPARE_METHOD nMethod,
									CFuncDescFile *pFile1, int nFile1FuncNdx,
									CFuncDescFile *pFile2, int nFile2FuncNdx,
									DWORD nOutputOptions,
									double &nMatchPercent,
									CSymbolMap *pSymbolMap)
{
	CString strRetVal = "";
	CString strEntry;
	CString strTemp;
	CStringArray oes;
	CStringArray Func1Lines;
	CStringArray Func2Lines;
	CFuncDesc *pFunction1;
	CFuncDesc *pFunction2;
	CFuncObject *pFuncObj;
	int i;
	int nLeftMax;
	int nRightMax;
	int nLeftIndex;
	int nRightIndex;
	int nLeftPos;
	int nRightPos;
	int nPos;

	if ((pFile1 == NULL) || (pFile2 == NULL)) return strRetVal;

	pFunction1 = pFile1->GetFunc(nFile1FuncNdx);
	pFunction2 = pFile2->GetFunc(nFile2FuncNdx);
	if ((pFunction1 == NULL) ||
		(pFunction2 == NULL)) return strRetVal;

	nMatchPercent = CompareFunctions(nMethod, pFile1, nFile1FuncNdx, pFile2, nFile2FuncNdx, TRUE);
	if (!GetLastEditScript(oes)) return strRetVal;

/*
// The following is for special debugging only:
	for (i=0; i<oes.GetSize(); i++) {
		strRetVal += "    " + oes.GetAt(i) + "\n";
	}
//	return strRetVal;
	strRetVal += "\n";
*/

	nLeftMax = 0;
	for (i=0; i<pFunction1->GetSize(); i++) {
		pFuncObj = pFunction1->GetAt(i);
		if (pFuncObj == NULL) {
			Func1Lines.Add("");
			continue;
		}
		strTemp = pFuncObj->CreateOutputLine(nOutputOptions);
		nLeftMax = __max(nLeftMax, strTemp.GetLength());
		Func1Lines.Add(strTemp);
	}

	nRightMax = 0;
	for (i=0; i<pFunction2->GetSize(); i++) {
		pFuncObj = pFunction2->GetAt(i);
		if (pFuncObj == NULL) {
			Func2Lines.Add("");
			continue;
		}
		strTemp = pFuncObj->CreateOutputLine(nOutputOptions);
		nRightMax = __max(nRightMax, strTemp.GetLength());
		Func2Lines.Add(strTemp);
	}

	strTemp = "";
	for (i=0; i<((nLeftMax-pFunction1->GetMainName().GetLength())/2); i++) strTemp += ' ';
	strRetVal += PadString(strTemp + pFunction1->GetMainName(), nLeftMax);

	strRetVal += "      ";

	strTemp = "";
	for (i=0; i<((nRightMax-pFunction2->GetMainName().GetLength())/2); i++) strTemp += ' ';
	strRetVal += PadString(strTemp + pFunction2->GetMainName(), nRightMax);

	strRetVal += "\n";

	for (i=0; i<nLeftMax; i++) strRetVal += '-';
	strRetVal += "      ";
	for (i=0; i<nRightMax; i++) strRetVal += '-';
	strRetVal += "\n";

	nLeftPos = 0;
	nRightPos = 0;
	for (i=0; i<oes.GetSize(); i++) {
		strEntry = oes.GetAt(i);
		nPos = strEntry.FindOneOf("<->");
		if (nPos == -1) continue;
		nLeftIndex = strtoul(strEntry.Left(nPos), NULL, 0);
		nRightIndex = strtoul(strEntry.Mid(nPos+1), NULL, 0);
		for (; ((nLeftPos < nLeftIndex) && (nRightPos < nRightIndex)); nLeftPos++, nRightPos++) {
			strRetVal += PadString(Func1Lines.GetAt(nLeftPos), nLeftMax);
			if (pFunction1->GetAt(nLeftPos)->IsExactMatch(pFunction2->GetAt(nRightPos))) {
				strRetVal += "  ==  ";
			} else {
				strRetVal += "  --  ";
			}
			strRetVal += Func2Lines.GetAt(nRightPos) + "\n";
			if (pSymbolMap) pSymbolMap->AddObjectMapping(*pFunction1->GetAt(nLeftPos), *pFunction2->GetAt(nRightPos));
		}
		ASSERT(nLeftPos == nLeftIndex);
		ASSERT(nRightPos == nRightIndex);

		#ifdef _DEBUG
		// The following is for special debugging only:
		if (nLeftPos != nLeftIndex) {
			strTemp.Format("\n\n*** ERROR: nLeftPos = %ld,  Expected = %ld\n\n", nLeftPos, nLeftIndex);
			strRetVal += strTemp;
			nLeftPos = nLeftIndex;
		}

		if (nRightPos != nRightIndex) {
			strTemp.Format("\n\n*** ERROR: nRightPos = %ld,  Expected = %ld\n\n", nRightPos, nRightIndex);
			strRetVal += strTemp;
			nRightPos = nRightIndex;
		}
		#endif

		#ifdef _DEBUG
		switch (strEntry.GetAt(nPos)) {
			case '<':
				if (nRightPos >= Func2Lines.GetSize()) {
					strRetVal += "\n\n*** ERROR: Right-Side Index Out-Of-Range!\n\n";
					return strRetVal;
				}
				break;
			case '-':
				if (nLeftPos >= Func1Lines.GetSize()) {
					strRetVal += "\n\n*** ERROR: Left-Side Index Out-Of-Range!\n\n";
					if (nRightPos >= Func2Lines.GetSize()) {
						strRetVal += "\n\n*** ERROR: Right-Side Index Out-Of-Range!\n\n";
					}
					return strRetVal;
				}
				if (nRightPos >= Func2Lines.GetSize()) {
					strRetVal += "\n\n*** ERROR: Right-Side Index Out-Of-Range!\n\n";
					return strRetVal;
				}
				break;
			case '>':
				if (nLeftPos >= Func1Lines.GetSize()) {
					strRetVal += "\n\n*** ERROR: Left-Side Index Out-Of-Range!\n\n";
					return strRetVal;
				}
				break;
		}
		#endif

		switch (strEntry.GetAt(nPos)) {
			case '<':				// Insert in Left
				strRetVal += PadString("", nLeftMax) + "  <<  " + Func2Lines.GetAt(nRightPos) + "\n";
				nRightPos++;
				break;

			case '-':				// Change
				strRetVal += PadString(Func1Lines.GetAt(nLeftPos), nLeftMax) + "  ->  " + Func2Lines.GetAt(nRightPos) + "\n";
				if (pSymbolMap) pSymbolMap->AddObjectMapping(*pFunction1->GetAt(nLeftPos), *pFunction2->GetAt(nRightPos));
				nLeftPos++;
				nRightPos++;
				break;

			case '>':				// Insert in Right
				strRetVal += PadString(Func1Lines.GetAt(nLeftPos), nLeftMax) + "  >>  \n";
				nLeftPos++;
				break;
		}
	}

	nLeftIndex = Func1Lines.GetSize();
	nRightIndex = Func2Lines.GetSize();
	for (; ((nLeftPos < nLeftIndex) && (nRightPos < nRightIndex)); nLeftPos++, nRightPos++) {
		strRetVal += PadString(Func1Lines.GetAt(nLeftPos), nLeftMax);
		if (pFunction1->GetAt(nLeftPos)->IsExactMatch(pFunction2->GetAt(nRightPos))) {
			strRetVal += "  ==  ";
		} else {
			strRetVal += "  --  ";
		}
		strRetVal += Func2Lines.GetAt(nRightPos) + "\n";
		if (pSymbolMap) pSymbolMap->AddObjectMapping(*pFunction1->GetAt(nLeftPos), *pFunction2->GetAt(nRightPos));
	}

	return strRetVal;
}

<file_sep>/programs/m6811dis/inteldfc.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      INTELDFC -- IntelHex DataFileConverter Class

      This is the C++ IntelHex DataFileConverter Object Class Header File.
      It is a child of the DFC Object class.

	  Author:  <NAME>
      Date:    January 29, 1997

      Written in: Borland C++ 4.52

      Updated: June 23, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

*/

#ifndef INTELDFC_H
#define INTELDFC_H

#include <iostream>
#include "dfc.h"
#include "memclass.h"
#include "errmsgs.h"

class TDFC_Intel : virtual public CDFCObject {
public:
	virtual std::string GetLibraryName(void) const { return "intel"; }
	virtual std::string GetShortDescription(void) const { return "Intel Hex Data File Converter"; }
	virtual std::string GetDescription(void) const { return "Intel Hex Data File Converter"; }

	const char *DefaultExtension(void) const { return "hex"; }

	int RetrieveFileMapping(std::istream *aFile, unsigned long NewBase, TMemRange *aRange) const;

	int ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, unsigned char aDesc) const;

	int WriteDataFile(std::ostream *aFile, TMemRange *aRange, unsigned long NewBase, TMemObject *aMemory,
								unsigned char aDesc, int UsePhysicalAddr, unsigned int FillMode) const;

private:
	int _ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, TMemRange *aRange, unsigned char aDesc) const;

};

#endif   // INTELDFC_H

<file_sep>/programs/funcanal/FuncView/FuncDiffEditView.h
// FuncDiffEditView.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncDiffEditView.h,v $
// Revision 1.1  2003/09/13 05:45:39  dewhisna
// Initial Revision
//
//

#if !defined(AFX_FUNCDIFFEDITVIEW_H__70724D9C_D78A_4475_AB58_24E1DA5853DC__INCLUDED_)
#define AFX_FUNCDIFFEDITVIEW_H__70724D9C_D78A_4475_AB58_24E1DA5853DC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "FuncViewPrjDoc.h"

/////////////////////////////////////////////////////////////////////////////
// CFuncDiffEditView view

class CFuncDiffEditView : public CEditView
{
protected:
	CFuncDiffEditView();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(CFuncDiffEditView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();
	CString m_strMatchPercentage;

protected:
	CFuncViewFuncRef m_LeftFunc;
	CFuncViewFuncRef m_RightFunc;

	CFont m_fntEditor;

	friend class CChildFrame2;

// Operations
public:

protected:
	void DoDiff();

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CFuncDiffEditView)
	public:
	virtual void OnInitialUpdate();
	protected:
	virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CFuncDiffEditView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

	// Generated message map functions
protected:
	//{{AFX_MSG(CFuncDiffEditView)
	afx_msg void OnSymbolsAdd();
	afx_msg void OnUpdateSymbolsAdd(CCmdUI* pCmdUI);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in FuncDiffEditView.cpp
inline CFuncViewPrjDoc* CFuncDiffEditView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_FUNCDIFFEDITVIEW_H__70724D9C_D78A_4475_AB58_24E1DA5853DC__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/ChildFrm6.cpp
// ChildFrm6.cpp : implementation file
//
// Frame Window for the CompDiffEdit Views
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm6.cpp,v $
// Revision 1.1  2003/09/13 05:45:35  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "ChildFrm6.h"

#include "CompDiffEditView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChildFrame6

IMPLEMENT_DYNCREATE(CChildFrame6, CChildFrameBase)

CChildFrame6::CChildFrame6()
{
}

CChildFrame6::~CChildFrame6()
{
}


BEGIN_MESSAGE_MAP(CChildFrame6, CChildFrameBase)
	//{{AFX_MSG_MAP(CChildFrame6)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildFrame6 message handlers

BOOL CChildFrame6::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	ASSERT(pContext != NULL);

	pContext->m_pNewViewClass = RUNTIME_CLASS(CCompDiffEditView);
	if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) return FALSE;

	return TRUE;

//	return CChildFrameBase::OnCreateClient(lpcs, pContext);
}

<file_sep>/support/ASxxxx/readme.txt
avxv5pxx_6811_no_opt.patch:

The avxv5pxx_6811_no_opt.patch patch file was created to remove the
direct addressing mode optimization in the 6811 Assembler, as
described in the M6811 Code-Seeking Disassembler documentation.

To apply, unzip the av5p06.zip file: 

On Linux and Mac, use:
unzip -L -a av5p06.zip
From the folder you unzip to, run:
patch -p1 < avxv5pxx_6811_no_opt.patch

On Windows, use:
unzip av5p06.zip
From the folder you unzip to, run:
patch -p1 < avxv5pxx_6811_no_opt_windows.patch

This will update the AS6811 assembler to not optimize addresses
in the 0x0000-0x00FF range to Direct (S_DIR) Addressing Mode
unless they are preceded by the "*" symbol and instead keep them
as Extended (S_EXT) Addressing Mode.

This is needed to make sure that code generated by the M6811DIS
program, when reassembled with the AS6811 assembler, will produce
the same original binary that was disassembled.

<file_sep>/programs/funcanal/funcdesc.cpp
// funcdesc.cpp: implementation of the CFuncDesc, CFuncDescFile, and CFuncObject classes.
//
// $Log: funcdesc.cpp,v $
// Revision 1.4  2003/09/13 05:38:03  dewhisna
// Added Read/Write File support.  Added output options on output line creation
// for function diff and added returning of match percentage.  Added callback
// function for read operation feedback.  Enhanced symbol map manipulation.
//
// Revision 1.3  2003/02/09 06:59:56  dewhisna
// Split comparison logic from Function File I/O
//
// Revision 1.2  2002/09/15 22:54:02  dewhisna
// Added Symbol Table comparison support
//
// Revision 1.1  2002/07/01 05:50:00  dewhisna
// Initial Revision
//
//

//
//	Format of Function Output File:
//
//		Any line beginning with a ";" is considered to be a commment line and is ignored
//
//		Memory Mapping:
//			#type|addr|size
//			   |    |    |____  Size of Mapped area (hex)
//			   |    |_________  Absolute Address of Mapped area (hex)
//			   |______________  Type of Mapped area (One of following: ROM, RAM, IO)
//
//		Label Definitions:
//			!addr|label
//			   |    |____ Label(s) for this address(comma separated)
//			   |_________ Absolute Address (hex)
//
//		Start of New Function:
//			@xxxx|name
//			   |    |____ Name(s) of Function (comma separated list)
//			   |_________ Absolute Address of Function Start relative to overall file (hex)
//
//		Mnemonic Line (inside function):
//			xxxx|xxxx|label|xxxxxxxxxx|xxxxxx|xxxx|DST|SRC|mnemonic|operands
//			  |    |    |        |        |     |   |   |     |        |____  Disassembled operand output (ascii)
//			  |    |    |        |        |     |   |   |     |_____________  Disassembled mnemonic (ascii)
//			  |    |    |        |        |     |   |___|___________________  See below for SRC/DST format
//			  |    |    |        |        |     |___________________________  Addressing/Data bytes from operand portion of instruction (hex)
//			  |    |    |        |        |_________________________________  Opcode bytes from instruction (hex)
//			  |    |    |        |__________________________________________  All bytes from instruction (hex)
//			  |    |    |___________________________________________________  Label(s) for this address (comma separated list)
//			  |    |________________________________________________________  Absolute address of instruction (hex)
//			  |_____________________________________________________________  Relative address of instruction to the function (hex)
//
//		Data Byte Line (inside function):
//			xxxx|xxxx|label|xx
//			  |    |    |    |____  Data Byte (hex)
//			  |    |    |_________  Label(s) for this address (comma separated)
//			  |    |______________  Absolute address of data byte (hex)
//			  |___________________  Relative address of data byte to the function (hex)
//
//		SRC and DST entries:
//			#xxxx			Immediate Data Value (xxxx=hex value)
//			C@xxxx			Absolute Code Address (xxxx=hex address)
//			C^n(xxxx)		Relative Code Address (n=signed offset in hex, xxxx=resolved absolute address in hex)
//			C&xx(r)			Register Code Offset (xx=hex offset, r=register number or name), ex: jmp 2,x -> "C$02(x)"
//			D@xxxx			Absolute Data Address (xxxx=hex address)
//			D^n(xxxx)		Relative Data Address (n=signed offset in hex, xxxx=resolved absolute address in hex)
//			D&xx(r)			Register Data Offset (xx=hex offset, r=register number or name), ex: ldaa 1,y -> "D$01(y)"
//
//			If any of the above also includes a mask, then the following will be added:
//			,Mxx			Value mask (xx=hex mask value)
//
//		Note: The address sizes are consistent with the particular process.  For example, an HC11 will
//			use 16-bit addresses (or 4 hex digits).  The size of immediate data entries, offsets, and masks will
//			reflect the actual value.  A 16-bit immediate value, offset, or mask, will be outputted as 4 hex
//			digits, but an 8-bit immediate value, offset, or mask, will be outputted as only 2 hex digits.
//

#include "stdafx.h"
//#include "funcanal.h"
#include "funcdesc.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

const static char m_strUnexpectedError[] = "Unexpected Error";
const static char m_strSyntaxError[] = "Syntax Error or Unexpected Entry";
const static char m_strOutOfMemoryError[] = "Out of Memory or Object Creation Error";


//////////////////////////////////////////////////////////////////////
// Static Functions
//////////////////////////////////////////////////////////////////////

// ParseLine : Parses a line from the file and returns an array of
//				items from the specified separator.
static void ParseLine(LPCTSTR pszLine, TCHAR cSepChar, CStringArray &argv)
{
	CString strLine = pszLine;
	CString strTemp;
	int pos;

	argv.RemoveAll();

	strLine += cSepChar;

	while (!strLine.IsEmpty()) {
		pos = strLine.Find(cSepChar);
		if (pos != -1) {
			strTemp = strLine.Left(pos);
			strTemp.TrimLeft();
			strTemp.TrimRight();
			strLine = strLine.Mid(pos+1);
		} else {
			strTemp = strLine;
			strTemp.TrimLeft();
			strTemp.TrimRight();
			strLine = "";
		}
		argv.Add(strTemp);
	}
}

// ReadFileString : Reads a line from an open CFile object and
//					fills in a CString object and returns a BOOL
//					of EOF status.  Is basically identical to
//					the CStdioFile ReadString function, but can
//					be any CFile derived object:
static BOOL ReadFileString(CFile &rFile, CString &rString)
{
	if (rFile.IsKindOf(RUNTIME_CLASS(CStdioFile))) return ((CStdioFile&)rFile).ReadString(rString);

	rString.Empty();

	TCHAR c = 0;
	UINT nBytesRead;
	while (((nBytesRead = rFile.Read(&c, sizeof(c))) != 0) && (c != 10)) {
		if (c != 10) rString += c;
	}
	if ((!rString.IsEmpty()) && (rString.GetAt(rString.GetLength()-1) == 13)) rString = rString.Left(rString.GetLength()-1);
	return ((nBytesRead != 0) || (!rString.IsEmpty()));
}

// WriteFileString : Writes a line to an open CFile object using
//					LF -> CRLF conversion as defined for text
//					files.  Is basically identical to the
//					CStdioFile WriteString function, but can be
//					any CFile derived object:
static void WriteFileString(CFile &rFile, LPCTSTR pszString)
{
	if (rFile.IsKindOf(RUNTIME_CLASS(CStdioFile))) {
		((CStdioFile&)rFile).WriteString(pszString);
		return;
	}

	CString strString = pszString;
	int pos;

	while ((pos = strString.Find('\n')) != -1) {
		if (pos != 0) rFile.Write(LPCTSTR(strString), pos);
		rFile.Write("\r\n", 2);
		strString = strString.Mid(pos+1);
	}
	if (!strString.IsEmpty()) rFile.Write(LPCTSTR(strString), strString.GetLength());
}


//////////////////////////////////////////////////////////////////////
// Global Functions
//////////////////////////////////////////////////////////////////////

// PadString : Pads a string with spaces up to the specified length.
CString PadString(LPCTSTR pszString, int nWidth)
{
	CString strRetVal = pszString;

	while (strRetVal.GetLength() < nWidth) strRetVal += ' ';
	return strRetVal;
}


//////////////////////////////////////////////////////////////////////
// CFuncObject Class
//////////////////////////////////////////////////////////////////////

CFuncObject::CFuncObject(CFuncDescFile &ParentFuncFile, CFuncDesc &ParentFunc, CStringArray &argv)
	:	m_ParentFuncFile(ParentFuncFile),
		m_ParentFunc(ParentFunc)
{
	ASSERT(argv.GetSize() >= 4);
	CStringArray strarrLabels;
	int i;
	CString strTemp;

	if (argv.GetSize() >= 1) m_dwRelFuncAddress = strtoul(argv[0], NULL, 16);
	if (argv.GetSize() >= 2) m_dwAbsAddress = strtoul(argv[1], NULL, 16);
	if (argv.GetSize() >= 3) {
		ParseLine(argv[2], ',', strarrLabels);
		for (i=0; i<strarrLabels.GetSize(); i++) AddLabel(strarrLabels.GetAt(i));
	}
	if (argv.GetSize() >= 4) {
		strTemp = argv[3];
		for (i=0; i<strTemp.GetLength()/2; i++) m_Bytes.Add((BYTE)strtoul(strTemp.Mid(i*2, 2), NULL, 16));
	}
}

CFuncObject::~CFuncObject()
{

}

BOOL CFuncObject::IsExactMatch(CFuncObject *pObj)
{
	int i;

	if (pObj == NULL) return FALSE;
	if (m_Bytes.GetSize() != pObj->m_Bytes.GetSize()) return FALSE;
	for (i=0; i<m_Bytes.GetSize(); i++) if (m_Bytes.GetAt(i) != pObj->m_Bytes.GetAt(i)) return FALSE;

	return TRUE;
}

BOOL CFuncObject::AddLabel(LPCTSTR pszLabel)
{
	CString strTemp;
	int i;

	if (pszLabel == NULL) return FALSE;
	strTemp = pszLabel;
	if (strTemp.IsEmpty()) return FALSE;

	// If we have the label already, return:
	for (i=0; i<m_LabelTable.GetSize(); i++) {
		if (strTemp.CompareNoCase(m_LabelTable.GetAt(i)) == 0) return FALSE;
	}
	m_LabelTable.Add(strTemp);
	return TRUE;
}

DWORD CFuncObject::GetRelFuncAddress()
{
	return m_dwRelFuncAddress;
}

DWORD CFuncObject::GetAbsAddress()
{
	return m_dwAbsAddress;
}

int CFuncObject::GetLabelCount()
{
	return m_LabelTable.GetSize();
}

CString CFuncObject::GetLabel(int nIndex)
{
	return m_LabelTable.GetAt(nIndex);
}

CString CFuncObject::GetBytes()
{
	CString strRetVal = "";
	CString strTemp;
	int i;

	for (i=0; i<m_Bytes.GetSize(); i++) {
		strTemp.Format("%02X", m_Bytes.GetAt(i));
		strRetVal +=  strTemp;
	}
	return strRetVal;
}

int CFuncObject::GetByteCount()
{
	return m_Bytes.GetSize();
}

void CFuncObject::GetSymbols(CStringArray &aSymbolArray)
{
	//
	// This function, and its override, fills in the passed in array as follows:
	//		Lxxxxxx			-- Label for THIS object, "xxxxxx = Label"
	//		RSCxxxxxx		-- Referenced by THIS object -- Source, Code, "xxxxxx = Label"
	//		RSDxxxxxx		-- Referenced by THIS object -- Source, Data, "xxxxxx = Label"
	//		RDCxxxxxx		-- Referenced by THIS object -- Destination, Code, "xxxxxx = Label"
	//		RDDxxxxxx		-- Referenced by THIS object -- Destination, Data, "xxxxxx = Label"
	//

	CString strTemp;

	aSymbolArray.RemoveAll();

	if (m_ParentFuncFile.AddrHasLabel(m_dwAbsAddress)) {
		strTemp = m_ParentFuncFile.GetPrimaryLabel(m_dwAbsAddress);
		if (!strTemp.IsEmpty()) {
			aSymbolArray.Add("L" + strTemp);
		}
	}
}

int CFuncObject::GetFieldWidth(FIELD_CODE nFC)
{
	switch (nFC) {
		case FC_ADDRESS:	return CALC_FIELD_WIDTH(7);
		case FC_OPBYTES:	return CALC_FIELD_WIDTH(11);
		case FC_LABEL:		return CALC_FIELD_WIDTH(13);
		case FC_MNEMONIC:	return CALC_FIELD_WIDTH(7);
		case FC_OPERANDS:	return CALC_FIELD_WIDTH(21);
		case FC_COMMENT:	return CALC_FIELD_WIDTH(60);
	}
	return 0;
}


//////////////////////////////////////////////////////////////////////
// CFuncAsmInstObject Class
//////////////////////////////////////////////////////////////////////

CFuncAsmInstObject::CFuncAsmInstObject(CFuncDescFile &ParentFuncFile, CFuncDesc &ParentFunc, CStringArray &argv)
	:	CFuncObject(ParentFuncFile, ParentFunc, argv)
{
	ASSERT(argv.GetSize() >= 10);
	int i;
	CString strTemp;

	if (argv.GetSize() >= 5) {
		strTemp = argv[4];
		for (i=0; i<strTemp.GetLength()/2; i++) m_OpCodeBytes.Add((BYTE)strtoul(strTemp.Mid(i*2, 2), NULL, 16));
	}
	if (argv.GetSize() >= 6) {
		strTemp = argv[5];
		for (i=0; i<strTemp.GetLength()/2; i++) m_OperandBytes.Add((BYTE)strtoul(strTemp.Mid(i*2, 2), NULL, 16));
	}
	if (argv.GetSize() >= 7) m_strDstOperand = argv[6];
	if (argv.GetSize() >= 8) m_strSrcOperand = argv[7];
	if (argv.GetSize() >= 9) m_strOpCodeText = argv[8];
	if (argv.GetSize() >= 10) m_strOperandText = argv[9];
}

CFuncAsmInstObject::~CFuncAsmInstObject()
{

}

CString CFuncAsmInstObject::ExportToDiff()
{
	CString strRetVal;
	CString strTemp;
	CString strTemp2;
	int i;
	DWORD nFuncStartAddr = m_ParentFunc.GetMainAddress();
	DWORD nFuncSize = m_ParentFunc.GetFuncSize();
	DWORD dwTemp;
	signed long snTemp;
	TMemRange zFuncRange(nFuncStartAddr, nFuncSize, 0);
	int pos;

	strRetVal.Format("C|%ld|", GetByteCount());
	strRetVal += GetOpCodeBytes();

	for (i=0; i<2; i++) {
		switch (i) {
			case 0:
				strTemp = m_strDstOperand;
				break;
			case 1:
				strTemp = m_strSrcOperand;
				break;
		}

		if (strTemp.IsEmpty()) continue;

		strRetVal += "|";

		switch (strTemp.GetAt(0)) {
			case '#':				// Immediate Data
				strRetVal += strTemp;
				break;
			case 'C':				// Code addressing
				if (strTemp.GetLength() < 2) continue;
				switch (strTemp.GetAt(1)) {
					case '@':		// Absolute
						dwTemp = strtoul(strTemp.Mid(2), NULL, 16);
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							strRetVal += "C=" + m_ParentFuncFile.GetPrimaryLabel(dwTemp);
						} else {
							// If there isn't a label, see if this absolute address lies inside the function:
							if (zFuncRange.AddressInRange(dwTemp)) {
								// If so, convert and treat as a relative address:
								snTemp = dwTemp - (GetAbsAddress() + GetByteCount());
								strTemp2.Format("C^%c%lX",
											((snTemp != labs(snTemp)) ? '-' : '+'),
											labs(snTemp));
								strRetVal += strTemp2;
							} else {
								// Otherwise, it is an outside reference to something unknown:
								strRetVal += "C?";
							}
						}
						// If there is a mask (or other appendage) add it:
						pos = strTemp.Find(',');
						if (pos != -1) strRetVal += strTemp.Mid(pos);
						break;
					case '^':		// Relative
						// Relative addressing is always relative to the "next byte" after the instruction:
						if (strTemp.GetLength() < 3) continue;
						pos = strTemp.Find('(', 3);
						if (pos != -1) {
							strTemp2 = strTemp.Mid(3, pos-3);
							pos = strTemp2.Find(')');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						} else {
							strTemp2 = strTemp.Mid(3);
							pos = strTemp2.Find(',');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						}
						snTemp = strtoul(strTemp2, NULL, 16);
						if (strTemp.GetAt(2) == '-') snTemp = 0 - snTemp;
						dwTemp = GetAbsAddress() + GetByteCount() + snTemp;		// Resolve address
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							strRetVal += "C=" + m_ParentFuncFile.GetPrimaryLabel(dwTemp);
						} else {
							// If there isn't a label, see if this relative address lies inside the function:
							if (zFuncRange.AddressInRange(dwTemp)) {
								// If so, continue to treat it as a relative address:
								strTemp2.Format("C^%c%lX",
											((snTemp != labs(snTemp)) ? '-' : '+'),
											labs(snTemp));
								strRetVal += strTemp2;
							} else {
								// Otherwise, it is an outside reference to something unknown:
								strRetVal += "C?";
							}
						}
						// If there is a mask (or other appendage) add it:
						pos = strTemp.Find(',');
						if (pos != -1) strRetVal += strTemp.Mid(pos);
						break;
					case '&':		// Reg. Offset
						strRetVal += strTemp;
						break;
				}
				break;
			case 'D':				// Data addressing
				if (strTemp.GetLength() < 2) continue;
				switch (strTemp.GetAt(1)) {
					case '@':		// Absolute
						dwTemp = strtoul(strTemp.Mid(2), NULL, 16);
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							strRetVal += "D=" + m_ParentFuncFile.GetPrimaryLabel(dwTemp);
						} else {
							// If there isn't a label, see if this absolute address lies inside the function:
							if (zFuncRange.AddressInRange(dwTemp)) {
								// If so, convert and treat as a relative address:
								snTemp = dwTemp - (GetAbsAddress() + GetByteCount());
								strTemp2.Format("D^%c%lX",
											((snTemp != labs(snTemp)) ? '-' : '+'),
											labs(snTemp));
								strRetVal += strTemp2;
							} else {
								// See if it is an I/O or NON-ROM/RAM location:
								if ((m_ParentFuncFile.IsIOMemAddr(dwTemp)) ||
									(!m_ParentFuncFile.IsROMMemAddr(dwTemp) && !m_ParentFuncFile.IsRAMMemAddr(dwTemp))) {
									// If so, treat create a label to reference it as it is significant:
									strTemp2.Format("D=L%04lX", dwTemp);
									strRetVal += strTemp2;
								} else {
									// Otherwise, it is an outside reference to something unknown in RAM/ROM
									//		and is probably a variable in memory that can move:
									strRetVal += "D?";
								}
							}
						}
						// If there is a mask (or other appendage) add it:
						pos = strTemp.Find(',');
						if (pos != -1) strRetVal += strTemp.Mid(pos);
						break;
					case '^':		// Relative
						// Relative addressing is always relative to the "next byte" after the instruction:
						if (strTemp.GetLength() < 3) continue;
						pos = strTemp.Find('(', 3);
						if (pos != -1) {
							strTemp2 = strTemp.Mid(3, pos-3);
							pos = strTemp2.Find(')');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						} else {
							strTemp2 = strTemp.Mid(3);
							pos = strTemp2.Find(',');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						}
						snTemp = strtoul(strTemp2, NULL, 16);
						if (strTemp.GetAt(2) == '-') snTemp = 0 - snTemp;
						dwTemp = GetAbsAddress() + GetByteCount() + snTemp;		// Resolve address
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							strRetVal += "D=" + m_ParentFuncFile.GetPrimaryLabel(dwTemp);
						} else {
							// If there isn't a label, see if this relative address lies inside the function:
							if (zFuncRange.AddressInRange(dwTemp)) {
								// If so, continue to treat it as a relative address:
								strTemp2.Format("D^%c%lX",
											((snTemp != labs(snTemp)) ? '-' : '+'),
											labs(snTemp));
								strRetVal += strTemp2;
							} else {
								// See if it is an I/O or NON-ROM/RAM location:
								if ((m_ParentFuncFile.IsIOMemAddr(dwTemp)) ||
									(!m_ParentFuncFile.IsROMMemAddr(dwTemp) && !m_ParentFuncFile.IsRAMMemAddr(dwTemp))) {
									// If so, treat create a label to reference it as it is significant:
									strTemp2.Format("D=L%04lX", dwTemp);
									strRetVal += strTemp2;
								} else {
									// Otherwise, it is an outside reference to something unknown in RAM/ROM
									//		and is probably a variable in memory that can move:
									strRetVal += "D?";
								}
							}
						}
						// If there is a mask (or other appendage) add it:
						pos = strTemp.Find(',');
						if (pos != -1) strRetVal += strTemp.Mid(pos);
						break;
					case '&':		// Reg. Offset
						strRetVal += strTemp;
						break;
				}
				break;
		}

	}

	return strRetVal;
}

void CFuncAsmInstObject::ExportToDiff(CStringArray &anArray)
{
	anArray.Add(ExportToDiff());
}

CString CFuncAsmInstObject::CreateOutputLine(DWORD nOutputOptions)
{
	CString strRetVal = "";
	CString strTemp;

	if (nOutputOptions & OO_ADD_ADDRESS) {
		strTemp.Format("%04lX ", m_dwAbsAddress);
		strRetVal += PadString(strTemp, GetFieldWidth(FC_ADDRESS));
	}

	strTemp = m_ParentFunc.GetPrimaryLabel(m_dwAbsAddress);
	strRetVal += PadString(strTemp + ((!strTemp.IsEmpty()) ? ": " : " "), GetFieldWidth(FC_LABEL));
	strRetVal += PadString(m_strOpCodeText + " ", GetFieldWidth(FC_MNEMONIC));
	strRetVal += PadString(m_strOperandText, GetFieldWidth(FC_OPERANDS));

	return strRetVal;
}

void CFuncAsmInstObject::GetSymbols(CStringArray &aSymbolArray)
{
	CString strTemp;
	CString strTemp2;
	CString strLabelPrefix;
	int i;
	DWORD dwTemp;
	signed long snTemp;
	int pos;

	// Call parent to build initial list:
	CFuncObject::GetSymbols(aSymbolArray);

	for (i=0; i<2; i++) {
		switch (i) {
			case 0:
				strTemp = m_strDstOperand;
				strLabelPrefix = "RD";
				break;
			case 1:
				strTemp = m_strSrcOperand;
				strLabelPrefix = "RS";
				break;
		}

		if (strTemp.IsEmpty()) continue;

		switch (strTemp.GetAt(0)) {
			case '#':				// Immediate Data
				break;
			case 'C':				// Code addressing
				if (strTemp.GetLength() < 2) continue;
				switch (strTemp.GetAt(1)) {
					case '@':		// Absolute
						dwTemp = strtoul(strTemp.Mid(2), NULL, 16);
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							aSymbolArray.Add(strLabelPrefix + "C" + m_ParentFuncFile.GetPrimaryLabel(dwTemp));
						} else {
							// Else, build a label:
							strTemp2.Format("L%04lX", dwTemp);
							aSymbolArray.Add(strLabelPrefix + "C" + strTemp2);
						}
						break;
					case '^':		// Relative
						// Relative addressing is always relative to the "next byte" after the instruction:
						if (strTemp.GetLength() < 3) continue;
						pos = strTemp.Find('(', 3);
						if (pos != -1) {
							strTemp2 = strTemp.Mid(3, pos-3);
							pos = strTemp2.Find(')');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						} else {
							strTemp2 = strTemp.Mid(3);
							pos = strTemp2.Find(',');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						}
						snTemp = strtoul(strTemp2, NULL, 16);
						if (strTemp.GetAt(2) == '-') snTemp = 0 - snTemp;
						dwTemp = GetAbsAddress() + GetByteCount() + snTemp;		// Resolve address
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							aSymbolArray.Add(strLabelPrefix + "C" + m_ParentFuncFile.GetPrimaryLabel(dwTemp));
						} else {
							// Else, build a label:
							strTemp2.Format("L%04lX", dwTemp);
							aSymbolArray.Add(strLabelPrefix + "C" + strTemp2);
						}
						break;
					case '&':		// Reg. Offset
						break;
				}
				break;
			case 'D':				// Data addressing
				if (strTemp.GetLength() < 2) continue;
				switch (strTemp.GetAt(1)) {
					case '@':		// Absolute
						dwTemp = strtoul(strTemp.Mid(2), NULL, 16);
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							aSymbolArray.Add(strLabelPrefix + "D" + m_ParentFuncFile.GetPrimaryLabel(dwTemp));
						} else {
							// Else, build a label:
							strTemp2.Format("L%04lX", dwTemp);
							aSymbolArray.Add(strLabelPrefix + "D" + strTemp2);
						}
						break;
					case '^':		// Relative
						// Relative addressing is always relative to the "next byte" after the instruction:
						if (strTemp.GetLength() < 3) continue;
						pos = strTemp.Find('(', 3);
						if (pos != -1) {
							strTemp2 = strTemp.Mid(3, pos-3);
							pos = strTemp2.Find(')');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						} else {
							strTemp2 = strTemp.Mid(3);
							pos = strTemp2.Find(',');
							if (pos != -1) strTemp2 = strTemp2.Left(pos);
						}
						snTemp = strtoul(strTemp2, NULL, 16);
						if (strTemp.GetAt(2) == '-') snTemp = 0 - snTemp;
						dwTemp = GetAbsAddress() + GetByteCount() + snTemp;		// Resolve address
						if (m_ParentFuncFile.AddrHasLabel(dwTemp)) {
							// If the address has a user-defined file-level label, use it instead:
							aSymbolArray.Add(strLabelPrefix + "D" + m_ParentFuncFile.GetPrimaryLabel(dwTemp));
						} else {
							// Else, build a label:
							strTemp2.Format("L%04lX", dwTemp);
							aSymbolArray.Add(strLabelPrefix + "D" + strTemp2);
						}
						break;
					case '&':		// Reg. Offset
						break;
				}
				break;
		}
	}
}

CString CFuncAsmInstObject::GetOpCodeBytes()
{
	CString strRetVal = "";
	CString strTemp;
	int i;

	for (i=0; i<m_OpCodeBytes.GetSize(); i++) {
		strTemp.Format("%02X", m_OpCodeBytes.GetAt(i));
		strRetVal +=  strTemp;
	}
	return strRetVal;
}

int CFuncAsmInstObject::GetOpCodeByteCount()
{
	return m_OpCodeBytes.GetSize();
}

CString CFuncAsmInstObject::GetOperandBytes()
{
	CString strRetVal = "";
	CString strTemp;
	int i;

	for (i=0; i<m_OperandBytes.GetSize(); i++) {
		strTemp.Format("%02X", m_OperandBytes.GetAt(i));
		strRetVal +=  strTemp;
	}
	return strRetVal;
}

int CFuncAsmInstObject::GetOperandByteCount()
{
	return m_OperandBytes.GetSize();
}


//////////////////////////////////////////////////////////////////////
// CFuncDataByteObject Class
//////////////////////////////////////////////////////////////////////
CFuncDataByteObject::CFuncDataByteObject(CFuncDescFile &ParentFuncFile, CFuncDesc &ParentFunc, CStringArray &argv)
	:	CFuncObject(ParentFuncFile, ParentFunc, argv)
{

}

CFuncDataByteObject::~CFuncDataByteObject()
{

}

CString CFuncDataByteObject::ExportToDiff()
{
	CString strRetVal;

	strRetVal.Format("D|%ld|", GetByteCount());
	strRetVal += GetBytes();
	return strRetVal;
}

void CFuncDataByteObject::ExportToDiff(CStringArray &anArray)
{
	anArray.Add(ExportToDiff());
}

CString CFuncDataByteObject::CreateOutputLine(DWORD nOutputOptions)
{
	CString strRetVal = "";
	CString strTemp;
	CString strTemp2;
	int i;

	if (nOutputOptions & OO_ADD_ADDRESS) {
		strTemp.Format("%04lX ", m_dwAbsAddress);
		strRetVal += PadString(strTemp, GetFieldWidth(FC_ADDRESS));
	}

	strTemp = m_ParentFunc.GetPrimaryLabel(m_dwAbsAddress);
	strRetVal += PadString(strTemp + ((!strTemp.IsEmpty()) ? ": " : " "), GetFieldWidth(FC_LABEL));
	strRetVal += PadString(".data ", GetFieldWidth(FC_MNEMONIC));
	strTemp2 = "";
	for (i=0; i<m_Bytes.GetSize(); i++) {
		if (i!=0) {
			strTemp.Format(", 0x%02X", m_Bytes.GetAt(i));
		} else {
			strTemp.Format("0x%02X", m_Bytes.GetAt(i));
		}
		strTemp2 += strTemp;
	}
	strRetVal += PadString(strTemp2, GetFieldWidth(FC_OPERANDS));

	return strRetVal;
}


//////////////////////////////////////////////////////////////////////
// CFuncDesc Class
//////////////////////////////////////////////////////////////////////

CFuncDesc::CFuncDesc(DWORD nAddress, LPCTSTR pszNames)
{
	CStringArray argv;
	int i;

	m_dwFunctionSize = 0;
	m_dwMainAddress = nAddress;

	ParseLine(pszNames, ',', argv);
	for (i=0; i<argv.GetSize(); i++) AddName(nAddress, argv[i]);
}

CFuncDesc::~CFuncDesc()
{
	FreeAll();
}

void CFuncDesc::FreeAll()
{
	CFuncObject *pFuncObject;
	int i;
	POSITION pos;
	DWORD anAddress;
	CStringArray *asArray;

	// Release function objects:
	for (i=0; i<GetSize(); i++) {
		pFuncObject = GetAt(i);
		if (pFuncObject) delete pFuncObject;
	}
	RemoveAll();

	// Release names table:
	pos = m_FuncNameTable.GetStartPosition();
	while (pos) {
		m_FuncNameTable.GetNextAssoc(pos, anAddress, asArray);
		if (asArray != NULL) delete asArray;
	}
	m_FuncNameTable.RemoveAll();

	// Release label table:
	pos = m_LabelTable.GetStartPosition();
	while (pos) {
		m_LabelTable.GetNextAssoc(pos, anAddress, asArray);
		if (asArray != NULL) delete asArray;
	}
	m_LabelTable.RemoveAll();
}

BOOL CFuncDesc::AddName(DWORD nAddress, LPCTSTR pszLabel)
{
	CStringArray *pNameList;
	CString strTemp;
	int i;

	if (pszLabel == NULL) return FALSE;
	strTemp = pszLabel;
	if (strTemp.IsEmpty()) return FALSE;
	if (m_FuncNameTable.Lookup(nAddress, pNameList)) {
		if (pNameList == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return FALSE;
		}
		// If we have the label already, return:
		for (i=0; i<pNameList->GetSize(); i++) {
			if (strTemp.CompareNoCase(pNameList->GetAt(i)) == 0) return FALSE;
		}
	} else {
		pNameList = new CStringArray;
		if (pNameList == NULL) AfxThrowMemoryException();
		m_FuncNameTable.SetAt(nAddress, pNameList);
	}
	ASSERT(pNameList != NULL);
	pNameList->Add(strTemp);
	return TRUE;
}

CString CFuncDesc::GetMainName()
{
	CStringArray *pNameList;
	CString strRetVal;

	strRetVal.Format("L%0lX", m_dwMainAddress);

	if (m_FuncNameTable.Lookup(m_dwMainAddress, pNameList)) {
		if (pNameList == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return strRetVal;
		}
		if (pNameList->GetSize() < 1)  return strRetVal;
		if (pNameList->GetAt(0).Compare("???") == 0) return strRetVal;
		return pNameList->GetAt(0);
	}

	return strRetVal;
}

DWORD CFuncDesc::GetMainAddress()
{
	return m_dwMainAddress;
}

BOOL CFuncDesc::AddLabel(DWORD nAddress, LPCTSTR pszLabel)
{
	CStringArray *pLabelList;
	CString strTemp;
	int i;

	if (pszLabel == NULL) return FALSE;
	strTemp = pszLabel;
	if (strTemp.IsEmpty()) return FALSE;
	if (m_LabelTable.Lookup(nAddress, pLabelList)) {
		if (pLabelList == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return FALSE;
		}
		// If we have the label already, return:
		for (i=0; i<pLabelList->GetSize(); i++) {
			if (strTemp.CompareNoCase(pLabelList->GetAt(i)) == 0) return FALSE;
		}
	} else {
		pLabelList = new CStringArray;
		if (pLabelList == NULL) AfxThrowMemoryException();
		m_LabelTable.SetAt(nAddress, pLabelList);
	}
	ASSERT(pLabelList != NULL);
	pLabelList->Add(strTemp);
	return TRUE;
}

BOOL CFuncDesc::AddrHasLabel(DWORD nAddress)
{
	CStringArray *pLabelList;

	if (m_LabelTable.Lookup(nAddress, pLabelList)) return TRUE;
	return FALSE;
}

CString CFuncDesc::GetPrimaryLabel(DWORD nAddress)
{
	CStringArray *pLabelList;

	if (m_LabelTable.Lookup(nAddress, pLabelList)) {
		if (pLabelList == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return "";
		}
		if (pLabelList->GetSize()<1) return "";
		return pLabelList->GetAt(0);
	}
	return "";
}

CStringArray *CFuncDesc::GetLabelList(DWORD nAddress)
{
	CStringArray *pLabelList;

	if (m_LabelTable.Lookup(nAddress, pLabelList)) return pLabelList;

	return NULL;
}

DWORD CFuncDesc::GetFuncSize()
{
//	CFuncObject *pFuncObject;
//	int i;
//	DWORD nRetVal;
//
//	nRetVal = 0;
//
//	// Add byte counts to get size:
//	for (i=0; i<GetSize(); i++) {
//		pFuncObject = GetAt(i);
//		if (pFuncObject) nRetVal += pFuncObject->GetByteCount();
//	}
//
//	return nRetVal;

	// For efficiency, the above has been replaced with the following:
	return m_dwFunctionSize;
}

CString CFuncDesc::ExportToDiff()
{
	CFuncObject *pFuncObject;
	int i;
	CString strRetVal;

	strRetVal = "";

	// Concatenate output from each member object to create composite:
	for (i=0; i<GetSize(); i++) {
		pFuncObject = GetAt(i);
		if (pFuncObject) strRetVal += pFuncObject->ExportToDiff() + "\n";
	}

	return strRetVal;
}

void CFuncDesc::ExportToDiff(CStringArray &anArray)
{
	CFuncObject *pFuncObject;
	int i;

	anArray.RemoveAll();

	// Add each item to array to create overall:
	for (i=0; i<GetSize(); i++) {
		pFuncObject = GetAt(i);
		if (pFuncObject) pFuncObject->ExportToDiff(anArray);
	}
}

int CFuncDesc::Add(CFuncObject *anObj)
{
	int i;
	DWORD nObjAddress;

	if (anObj) {
		nObjAddress = anObj->GetAbsAddress();
		for (i=0; i<anObj->GetLabelCount(); i++) {
			AddLabel(nObjAddress, anObj->GetLabel(i));
		}
		m_dwFunctionSize += anObj->GetByteCount();
		return CTypedPtrArray<CObArray, CFuncObject *>::Add(anObj);
	}

	return -1;
}


//////////////////////////////////////////////////////////////////////
// CFuncDescFile Class
//////////////////////////////////////////////////////////////////////

CFuncDescFile::CFuncDescFile()
	:	m_ROMMemMap(0, 0, 0),
		m_RAMMemMap(0, 0, 0),
		m_IOMemMap(0, 0, 0)
{
	ParseCmdsOP1.SetAt("ROM", 0);
	ParseCmdsOP1.SetAt("RAM", 1);
	ParseCmdsOP1.SetAt("IO", 2);

	m_pfnProgressCallback = NULL;
	m_lParamProgressCallback = 0;
}

CFuncDescFile::~CFuncDescFile()
{
	FreeAll();
}

void CFuncDescFile::FreeAll()
{
	POSITION pos;
	DWORD anAddress;
	CStringArray *asArray;
	CFuncDesc *pFuncDesc;
	int i;

	// Release Functions:
	for (i=0; i<m_Functions.GetSize(); i++) {
		pFuncDesc = m_Functions.GetAt(i);
		if (pFuncDesc) delete pFuncDesc;
	}
	m_Functions.RemoveAll();

	// Release label table:
	pos = m_LabelTable.GetStartPosition();
	while (pos) {
		m_LabelTable.GetNextAssoc(pos, anAddress, asArray);
		if (asArray != NULL) delete asArray;
	}
	m_LabelTable.RemoveAll();
}

BOOL CFuncDescFile::ReadFuncDescFile(CFile& inFile, CFile *msgFile, CFile *errFile, int nStartLineCount)
{
	CString strLine;
	CString strTemp;
	int nLineCount = nStartLineCount;
	CFuncDesc *pCurrentFunction = NULL;
	CFuncObject *pFuncObj;
	BOOL bRetVal = TRUE;
	CString strError = m_strUnexpectedError;
	WORD nParseVal;
	DWORD nTemp;
	DWORD nAddress;
	DWORD nSize;
	BOOL bTemp;
	CStringArray argv;
	int i,j;
	TMemRange *pMemRange;
	CDWordArray SortedList;
	CStringArray *pStrArray;
	POSITION mpos;

#define BUSY_CALLBACK_RATE 50
#define BUSY_CALLBACK_RATE2 10

	if (msgFile) {
		strTemp = "Reading Function Definition File \"" + inFile.GetFileName() + "\"...\n";
		WriteFileString(*msgFile, strTemp);
	}

	m_strFilePathName = inFile.GetFilePath();
	m_strFileName = inFile.GetFileName();

	while ((bRetVal) && (ReadFileString(inFile, strLine))) {
		nLineCount++;
		strLine.TrimLeft();
		strLine.TrimRight();

		if ((m_pfnProgressCallback) && ((nLineCount % BUSY_CALLBACK_RATE) == 0))
			m_pfnProgressCallback(0, 1, FALSE, m_lParamProgressCallback);

		// Empty lines are ignored:
		if (strLine.IsEmpty()) continue;

		switch (strLine.GetAt(0)) {
			case ';':			// Comments
				// Ignore comment lines:
				break;

			case '#':			// Memory Mapping
				pCurrentFunction = NULL;

				ParseLine(strLine.Mid(1), '|', argv);
				if (argv.GetSize() != 3) {
					strError = m_strSyntaxError;
					bRetVal = FALSE;
					break;
				}

				if (!ParseCmdsOP1.Lookup(argv[0], nParseVal)) {
					strError = m_strSyntaxError;
					bRetVal = FALSE;
					break;
				}

				nAddress = strtoul(argv[1], NULL, 16);
				nSize = strtoul(argv[2], NULL, 16);

				switch (nParseVal) {
					case 0:		// ROM
						m_ROMMemMap.AddRange(nAddress, nSize, 0);
						m_ROMMemMap.Compact();
						m_ROMMemMap.RemoveOverlaps();
						m_ROMMemMap.Sort();
						bTemp = TRUE;
						if (errFile) {
							for (nTemp = nAddress; ((nTemp < (nAddress + nSize)) && (bTemp)); nTemp++) {
								if (m_RAMMemMap.AddressInRange(nTemp)) {
									bTemp = FALSE;
									WriteFileString(*errFile, "*** Warning: Specified ROM Mapping conflicts with RAM Mapping\n");
								} else {
									if (m_IOMemMap.AddressInRange(nTemp)) {
										bTemp = FALSE;
										WriteFileString(*errFile, "*** Warning: Specified ROM Mapping conflicts with IO Mapping\n");
									}
								}
							}
						}
						break;
					case 1:		// RAM
						m_RAMMemMap.AddRange(nAddress, nSize, 0);
						m_RAMMemMap.Compact();
						m_RAMMemMap.RemoveOverlaps();
						m_RAMMemMap.Sort();
						bTemp = TRUE;
						if (errFile) {
							for (nTemp = nAddress; ((nTemp < (nAddress + nSize)) && (bTemp)); nTemp++) {
								if (m_ROMMemMap.AddressInRange(nTemp)) {
									bTemp = FALSE;
									WriteFileString(*errFile, "*** Warning: Specified RAM Mapping conflicts with ROM Mapping\n");
								} else {
									if (m_IOMemMap.AddressInRange(nTemp)) {
										bTemp = FALSE;
										WriteFileString(*errFile, "*** Warning: Specified RAM Mapping conflicts with IO Mapping\n");
									}
								}
							}
						}
						break;
					case 2:		// IO
						m_IOMemMap.AddRange(nAddress, nSize, 0);
						m_IOMemMap.Compact();
						m_IOMemMap.RemoveOverlaps();
						m_IOMemMap.Sort();
						bTemp = TRUE;
						if (errFile) {
							for (nTemp = nAddress; ((nTemp < (nAddress + nSize)) && (bTemp)); nTemp++) {
								if (m_ROMMemMap.AddressInRange(nTemp)) {
									bTemp = FALSE;
									WriteFileString(*errFile, "*** Warning: Specified IO Mapping conflicts with ROM Mapping\n");
								} else {
									if (m_RAMMemMap.AddressInRange(nTemp)) {
										bTemp = FALSE;
										WriteFileString(*errFile, "*** Warning: Specified IO Mapping conflicts with RAM Mapping\n");
									}
								}
							}
						}
						break;
				}
				break;

			case '!':			// Label
				pCurrentFunction = NULL;

				ParseLine(strLine.Mid(1), '|', argv);
				if (argv.GetSize() != 2) {
					strError = m_strSyntaxError;
					bRetVal = FALSE;
					break;
				}

				nAddress = strtoul(argv[0], NULL, 16);
				ParseLine(argv[1], ',', argv);

				for (i=0; i<argv.GetSize(); i++) {
					AddLabel(nAddress, argv[i]);
				}
				break;

			case '@':			// New Function declaration:
				pCurrentFunction = NULL;

				ParseLine(strLine.Mid(1), '|', argv);
				if (argv.GetSize() != 2) {
					strError = m_strSyntaxError;
					bRetVal = FALSE;
					break;
				}

				nAddress = strtoul(argv[0], NULL, 16);

				pCurrentFunction = new CFuncDesc(nAddress, argv[1]);
				if (pCurrentFunction == NULL) {
					strError = m_strOutOfMemoryError;
					bRetVal = FALSE;
					break;
				}
				m_Functions.Add(pCurrentFunction);
				break;

			default:
				// See if we are in the middle of a function declaration:
				if (pCurrentFunction == NULL) {
					// If we aren't in a function, it's a syntax error:
					strError = m_strSyntaxError;
					bRetVal = FALSE;
					break;
				}

				// If we are in a function, parse entry:
				if (isxdigit(strLine.GetAt(0))) {
					ParseLine(strLine, '|', argv);
					if ((argv.GetSize() != 4) &&
						(argv.GetSize() != 10)) {
						strError = m_strSyntaxError;
						bRetVal = FALSE;
						break;
					}

					pFuncObj = NULL;
					if (argv.GetSize() == 4) {
						pFuncObj = new CFuncDataByteObject(*this, *pCurrentFunction, argv);
					} else {
						pFuncObj = new CFuncAsmInstObject(*this, *pCurrentFunction, argv);
					}
					pCurrentFunction->Add(pFuncObj);

				} else {
					strError = m_strSyntaxError;
					bRetVal = FALSE;
				}
				break;
		}
	}

	if ((bRetVal) && (msgFile)) {
		WriteFileString(*msgFile, "\n");

		WriteFileString(*msgFile, "    Memory Mappings:\n");
		WriteFileString(*msgFile, "        ROM Memory Map:");
		if (m_ROMMemMap.IsNullRange()) {
			WriteFileString(*msgFile, " <Not Defined>\n");
		} else {
			WriteFileString(*msgFile, "\n");
			pMemRange = &m_ROMMemMap;
			while (pMemRange) {
				strTemp.Format("            0x%04lX - 0x%04lX  (Size: 0x%04lX)\n",
							pMemRange->GetStartAddr(),
							pMemRange->GetStartAddr() + pMemRange->GetSize() - 1,
							pMemRange->GetSize());
				WriteFileString(*msgFile, strTemp);
				pMemRange = pMemRange->GetNext();
			}
		}
		WriteFileString(*msgFile, "        RAM Memory Map:");
		if (m_RAMMemMap.IsNullRange()) {
			WriteFileString(*msgFile, " <Not Defined>\n");
		} else {
			WriteFileString(*msgFile, "\n");
			pMemRange = &m_RAMMemMap;
			while (pMemRange) {
				strTemp.Format("            0x%04lX - 0x%04lX  (Size: 0x%04lX)\n",
							pMemRange->GetStartAddr(),
							pMemRange->GetStartAddr() + pMemRange->GetSize() - 1,
							pMemRange->GetSize());
				WriteFileString(*msgFile, strTemp);
				pMemRange = pMemRange->GetNext();
			}
		}
		WriteFileString(*msgFile, "         IO Memory Map:");
		if (m_IOMemMap.IsNullRange()) {
			WriteFileString(*msgFile, " <Not Defined>\n");
		} else {
			WriteFileString(*msgFile, "\n");
			pMemRange = &m_IOMemMap;
			while (pMemRange) {
				strTemp.Format("            0x%04lX - 0x%04lX  (Size: 0x%04lX)\n",
							pMemRange->GetStartAddr(),
							pMemRange->GetStartAddr() + pMemRange->GetSize() - 1,
							pMemRange->GetSize());
				WriteFileString(*msgFile, strTemp);
				pMemRange = pMemRange->GetNext();
			}
		}
		WriteFileString(*msgFile, "\n");

		strTemp.Format("    %ld Function%s defined%s\n",
									m_Functions.GetSize(),
									((m_Functions.GetSize() != 1) ? "s" : ""),
									((m_Functions.GetSize() != 0) ? ":" : ""));
		WriteFileString(*msgFile, strTemp);
		for (i=0; i<m_Functions.GetSize(); i++) {
			strTemp.Format("        %04lX -> %s\n", m_Functions.GetAt(i)->GetMainAddress(), LPCTSTR(m_Functions.GetAt(i)->GetMainName()));
			WriteFileString(*msgFile, strTemp);

			if ((m_pfnProgressCallback) && ((i % BUSY_CALLBACK_RATE2) == 0))
				m_pfnProgressCallback(0, 1, FALSE, m_lParamProgressCallback);
		}
		WriteFileString(*msgFile, "\n");


		strTemp.Format("    %ld Unique Label%s Defined%s\n",
									m_LabelTable.GetCount(),
									((m_LabelTable.GetCount() != 1) ? "s" : ""),
									((m_LabelTable.GetCount() != 0) ? ":" : ""));
		WriteFileString(*msgFile, strTemp);
		SortedList.RemoveAll();
		mpos = m_LabelTable.GetStartPosition();
		while (mpos) {
			m_LabelTable.GetNextAssoc(mpos, nAddress, pStrArray);
			bTemp = FALSE;
			for (i=0; ((i<SortedList.GetSize()) && (bTemp == FALSE)); i++) {
				if (nAddress <= SortedList.GetAt(i)) {
					SortedList.InsertAt(i, nAddress);
					bTemp = TRUE;
				}
			}
			if (bTemp == FALSE) SortedList.Add(nAddress);
		}
		for (i=0; i<SortedList.GetSize(); i++) {
			m_LabelTable.Lookup(SortedList.GetAt(i), pStrArray);
			strTemp.Format("        0x%04lX=", SortedList.GetAt(i));
			WriteFileString(*msgFile, strTemp);
			if (pStrArray) {
				for (j=0; j<pStrArray->GetSize(); j++) {
					if (j != 0) WriteFileString(*msgFile, ",");
					WriteFileString(*msgFile, pStrArray->GetAt(j));
				}
			}
			WriteFileString(*msgFile, "\n");

			if ((m_pfnProgressCallback) && ((i % BUSY_CALLBACK_RATE2) == 0))
				m_pfnProgressCallback(0, 1, FALSE, m_lParamProgressCallback);
		}
		WriteFileString(*msgFile, "\n");
	}

	if ((bRetVal == FALSE) && (errFile)) {
		strTemp.Format("*** Error: %s : on line %ld of file\n           \"%s\"\n",
							LPCTSTR(strError), nLineCount, LPCTSTR(inFile.GetFilePath()));
		WriteFileString(*errFile, strTemp);
	}

	return bRetVal;
}

BOOL CFuncDescFile::AddLabel(DWORD nAddress, LPCTSTR pszLabel)
{
	CStringArray *pLabelList;
	CString strTemp;
	int i;

	if (pszLabel == NULL) return FALSE;
	strTemp = pszLabel;
	if (strTemp.IsEmpty()) return FALSE;
	if (m_LabelTable.Lookup(nAddress, pLabelList)) {
		if (pLabelList == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return FALSE;
		}
		// If we have the label already, return:
		for (i=0; i<pLabelList->GetSize(); i++) {
			if (strTemp.CompareNoCase(pLabelList->GetAt(i)) == 0) return FALSE;
		}
	} else {
		pLabelList = new CStringArray;
		if (pLabelList == NULL) AfxThrowMemoryException();
		m_LabelTable.SetAt(nAddress, pLabelList);
	}
	ASSERT(pLabelList != NULL);
	pLabelList->Add(strTemp);
	return TRUE;
}

BOOL CFuncDescFile::AddrHasLabel(DWORD nAddress)
{
	CStringArray *pLabelList;

	if (m_LabelTable.Lookup(nAddress, pLabelList)) return TRUE;
	return FALSE;
}

CString CFuncDescFile::GetPrimaryLabel(DWORD nAddress)
{
	CStringArray *pLabelList;

	if (m_LabelTable.Lookup(nAddress, pLabelList)) {
		if (pLabelList == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return "";
		}
		if (pLabelList->GetSize()<1) return "";
		return pLabelList->GetAt(0);
	}
	return "";
}

CStringArray *CFuncDescFile::GetLabelList(DWORD nAddress)
{
	CStringArray *pLabelList;

	if (m_LabelTable.Lookup(nAddress, pLabelList)) return pLabelList;

	return NULL;
}

int CFuncDescFile::GetFuncCount()
{
	return m_Functions.GetSize();
}

CFuncDesc *CFuncDescFile::GetFunc(int nIndex)
{
	return m_Functions.GetAt(nIndex);
}

CString CFuncDescFile::GetFuncPathName()
{
	return m_strFilePathName;
}

CString CFuncDescFile::GetFuncFileName()
{
	return m_strFileName;
}

BOOL CFuncDescFile::IsROMMemAddr(DWORD nAddress)
{
	return m_ROMMemMap.AddressInRange(nAddress);
}

BOOL CFuncDescFile::IsRAMMemAddr(DWORD nAddress)
{
	return m_RAMMemMap.AddressInRange(nAddress);
}

BOOL CFuncDescFile::IsIOMemAddr(DWORD nAddress)
{
	return m_IOMemMap.AddressInRange(nAddress);
}


//////////////////////////////////////////////////////////////////////
// CFuncDescFileArray Class
//////////////////////////////////////////////////////////////////////

CFuncDescFileArray::CFuncDescFileArray()
{
	m_pfnProgressCallback = NULL;
	m_lParamProgressCallback = 0;
}

CFuncDescFileArray::~CFuncDescFileArray()
{
	FreeAll();
}

void CFuncDescFileArray::FreeAll()
{
	CFuncDescFile *pFuncDescFileObj;
	int i;

	// Release function objects:
	for (i=0; i<GetSize(); i++) {
		pFuncDescFileObj = GetAt(i);
		if (pFuncDescFileObj) delete pFuncDescFileObj;
	}
	RemoveAll();
}

int CFuncDescFileArray::GetFuncCount()
{
	int nRetVal = 0;
	int i;
	CFuncDescFile *pFuncDescFile;

	for (i=0; i<GetSize(); i++) {
		pFuncDescFile = GetAt(i);
		if (pFuncDescFile == NULL) continue;
		nRetVal += pFuncDescFile->GetFuncCount();
	}

	return nRetVal;
}

double CFuncDescFileArray::CompareFunctions(FUNC_COMPARE_METHOD nMethod,
											int nFile1Ndx, int nFile1FuncNdx,
											int nFile2Ndx, int nFile2FuncNdx,
											BOOL bBuildEditScript)
{
	CFuncDescFile *pFuncDescFile1Obj;
	CFuncDescFile *pFuncDescFile2Obj;

	pFuncDescFile1Obj = GetAt(nFile1Ndx);
	pFuncDescFile2Obj = GetAt(nFile2Ndx);

	return ::CompareFunctions(nMethod, pFuncDescFile1Obj, nFile1FuncNdx, pFuncDescFile2Obj, nFile2FuncNdx, bBuildEditScript);
}

CString CFuncDescFileArray::DiffFunctions(FUNC_COMPARE_METHOD nMethod,
									int nFile1Ndx, int nFile1FuncNdx,
									int nFile2Ndx, int nFile2FuncNdx,
									DWORD nOutputOptions,
									double &nMatchPercent,
									CSymbolMap *pSymbolMap)
{
	CFuncDescFile *pFuncDescFile1Obj;
	CFuncDescFile *pFuncDescFile2Obj;

	pFuncDescFile1Obj = GetAt(nFile1Ndx);
	pFuncDescFile2Obj = GetAt(nFile2Ndx);

	return ::DiffFunctions(nMethod, pFuncDescFile1Obj, nFile1FuncNdx, pFuncDescFile2Obj, nFile2FuncNdx,
							nOutputOptions, nMatchPercent, pSymbolMap);
}


//////////////////////////////////////////////////////////////////////
// CSymbolMap Class
//////////////////////////////////////////////////////////////////////

CSymbolMap::CSymbolMap()
{

}

CSymbolMap::~CSymbolMap()
{
	FreeAll();
}

void CSymbolMap::FreeAll()
{
	CStringArray *pArray;
	CString strTemp;
	POSITION pos;

	pos = m_LeftSideCodeSymbols.GetStartPosition();
	while (pos) {
		m_LeftSideCodeSymbols.GetNextAssoc(pos, strTemp, pArray);
		if (pArray != NULL) delete pArray;
	}
	m_LeftSideCodeSymbols.RemoveAll();

	pos = m_RightSideCodeSymbols.GetStartPosition();
	while (pos) {
		m_RightSideCodeSymbols.GetNextAssoc(pos, strTemp, pArray);
		if (pArray != NULL) delete pArray;
	}
	m_RightSideCodeSymbols.RemoveAll();

	pos = m_LeftSideDataSymbols.GetStartPosition();
	while (pos) {
		m_LeftSideDataSymbols.GetNextAssoc(pos, strTemp, pArray);
		if (pArray != NULL) delete pArray;
	}
	m_LeftSideDataSymbols.RemoveAll();

	pos = m_RightSideDataSymbols.GetStartPosition();
	while (pos) {
		m_RightSideDataSymbols.GetNextAssoc(pos, strTemp, pArray);
		if (pArray != NULL) delete pArray;
	}
	m_RightSideDataSymbols.RemoveAll();
}

BOOL CSymbolMap::IsEmpty()
{
	if (m_LeftSideCodeSymbols.GetCount() != 0) return FALSE;
	if (m_RightSideCodeSymbols.GetCount() != 0) return FALSE;
	if (m_LeftSideDataSymbols.GetCount() != 0) return FALSE;
	if (m_RightSideDataSymbols.GetCount() != 0) return FALSE;

	return TRUE;
}

void CSymbolMap::AddObjectMapping(CFuncObject &aLeftObject, CFuncObject &aRightObject)
{
	CStringArray arrLeftSymbols;
	CStringArray arrRightSymbols;
	int i;
	int j;
	CString strTemp1;
	CString strTemp2;
	BOOL bFlag;
	BOOL bFlag2;
	int nMode;		// 0 = Source, 1 = Destination
	int nType;		// 0 = Code, 1 = Data

	aLeftObject.GetSymbols(arrLeftSymbols);
	aRightObject.GetSymbols(arrRightSymbols);

	// Since we are comparing functions, any "L" entries are automatically "Code" entries:
	for (i=0; i<arrLeftSymbols.GetSize(); i++) {
		strTemp1 = arrLeftSymbols.GetAt(i);
		if ((strTemp1.IsEmpty()) || (strTemp1.GetAt(0) != 'L')) continue;
		if (strTemp1.GetLength() < 2) continue;
		bFlag = FALSE;
		for (j=0; j<arrRightSymbols.GetSize(); j++) {
			strTemp2 = arrRightSymbols.GetAt(j);
			if ((strTemp2.IsEmpty()) || (strTemp2.GetAt(0) != 'L')) continue;
			if (strTemp2.GetLength() < 2) continue;
			AddLeftSideCodeSymbol(strTemp1.Mid(1), strTemp2.Mid(1));
			bFlag = TRUE;
		}
		if (!bFlag) AddLeftSideCodeSymbol(strTemp1.Mid(1), "");
	}

	for (i=0; i<arrRightSymbols.GetSize(); i++) {
		strTemp1 = arrRightSymbols.GetAt(i);
		if ((strTemp1.IsEmpty()) || (strTemp1.GetAt(0) != 'L')) continue;
		if (strTemp1.GetLength() < 2) continue;
		bFlag = FALSE;
		for (j=0; j<arrLeftSymbols.GetSize(); j++) {
			strTemp2 = arrLeftSymbols.GetAt(j);
			if ((strTemp2.IsEmpty()) || (strTemp2.GetAt(0) != 'L')) continue;
			if (strTemp2.GetLength() < 2) continue;
			AddRightSideCodeSymbol(strTemp1.Mid(1), strTemp2.Mid(1));
			bFlag = TRUE;
		}
		if (!bFlag) AddRightSideCodeSymbol(strTemp1.Mid(1), "");
	}

	// Add Left Source/Destination entries:
	for (i=0; i<arrLeftSymbols.GetSize(); i++) {
		strTemp1 = arrLeftSymbols.GetAt(i);
		if ((strTemp1.IsEmpty()) || (strTemp1.GetAt(0) != 'R')) continue;
		if (strTemp1.GetLength() < 4) continue;
		switch (strTemp1.GetAt(1)) {
			case 'S':
				nMode = 0;
				break;
			case 'D':
				nMode = 1;
				break;
			default:
				continue;
		}
		switch (strTemp1.GetAt(2)) {
			case 'C':
				nType = 0;
				break;
			case 'D':
				nType = 1;
				break;
			default:
				continue;
		}
		bFlag = FALSE;
		for (j=0; j<arrRightSymbols.GetSize(); j++) {
			strTemp2 = arrRightSymbols.GetAt(j);
			if ((strTemp2.IsEmpty()) || (strTemp2.GetAt(0) != 'R')) continue;
			if (strTemp2.GetLength() < 4) continue;
			bFlag2 = FALSE;
			switch (strTemp2.GetAt(1)) {
				case 'S':
					if (nMode == 0) {
						bFlag2 = TRUE;
					}
					break;
				case 'D':
					if (nMode == 1) {
						bFlag2 = TRUE;
					}
					break;
				default:
					continue;
			}
			if (bFlag2) {
				switch (strTemp2.GetAt(2)) {
					case 'C':
						if (nType == 0) {
							AddLeftSideCodeSymbol(strTemp1.Mid(3), strTemp2.Mid(3));
							bFlag = TRUE;
						}
						break;
					case 'D':
						if (nType == 1) {
							AddLeftSideDataSymbol(strTemp1.Mid(3), strTemp2.Mid(3));
							bFlag = TRUE;
						}
						break;
					default:
						continue;
				}
			}
		}
		if (!bFlag) {
			switch (nType) {
				case 0:
					AddLeftSideCodeSymbol(strTemp1.Mid(3), "");
					break;
				case 1:
					AddLeftSideDataSymbol(strTemp1.Mid(3), "");
					break;
			}
		}
	}

	// Add Right Source/Destination entries:
	for (i=0; i<arrRightSymbols.GetSize(); i++) {
		strTemp1 = arrRightSymbols.GetAt(i);
		if ((strTemp1.IsEmpty()) || (strTemp1.GetAt(0) != 'R')) continue;
		if (strTemp1.GetLength() < 4) continue;
		switch (strTemp1.GetAt(1)) {
			case 'S':
				nMode = 0;
				break;
			case 'D':
				nMode = 1;
				break;
			default:
				continue;
		}
		switch (strTemp1.GetAt(2)) {
			case 'C':
				nType = 0;
				break;
			case 'D':
				nType = 1;
				break;
			default:
				continue;
		}
		bFlag = FALSE;
		for (j=0; j<arrLeftSymbols.GetSize(); j++) {
			strTemp2 = arrLeftSymbols.GetAt(j);
			if ((strTemp2.IsEmpty()) || (strTemp2.GetAt(0) != 'R')) continue;
			if (strTemp2.GetLength() < 4) continue;
			bFlag2 = FALSE;
			switch (strTemp2.GetAt(1)) {
				case 'S':
					if (nMode == 0) {
						bFlag2 = TRUE;
					}
					break;
				case 'D':
					if (nMode == 1) {
						bFlag2 = TRUE;
					}
					break;
				default:
					continue;
			}
			if (bFlag2) {
				switch (strTemp2.GetAt(2)) {
					case 'C':
						if (nType == 0) {
							AddRightSideCodeSymbol(strTemp1.Mid(3), strTemp2.Mid(3));
							bFlag = TRUE;
						}
						break;
					case 'D':
						if (nType == 1) {
							AddRightSideDataSymbol(strTemp1.Mid(3), strTemp2.Mid(3));
							bFlag = TRUE;
						}
						break;
					default:
						continue;
				}
			}
		}
		if (!bFlag) {
			switch (nType) {
				case 0:
					AddRightSideCodeSymbol(strTemp1.Mid(3), "");
					break;
				case 1:
					AddRightSideDataSymbol(strTemp1.Mid(3), "");
					break;
			}
		}
	}
}

void CSymbolMap::GetLeftSideCodeSymbolList(CStringArray &anArray)
{
	GetSymbolList(m_LeftSideCodeSymbols, anArray);
}

void CSymbolMap::GetRightSideCodeSymbolList(CStringArray &anArray)
{
	GetSymbolList(m_RightSideCodeSymbols, anArray);
}

void CSymbolMap::GetLeftSideDataSymbolList(CStringArray &anArray)
{
	GetSymbolList(m_LeftSideDataSymbols, anArray);
}

void CSymbolMap::GetRightSideDataSymbolList(CStringArray &anArray)
{
	GetSymbolList(m_RightSideDataSymbols, anArray);
}

void CSymbolMap::GetSymbolList(CMap<CString, LPCTSTR, CStringArray*, CStringArray*> &mapSymbolArrays,
								CStringArray &anArray)
{
	POSITION pos;
	CString strTemp;
	CStringArray *pArray;
	int i;

	anArray.RemoveAll();

	pos = mapSymbolArrays.GetStartPosition();
	while (pos) {
		mapSymbolArrays.GetNextAssoc(pos, strTemp, pArray);
		for (i=0; i<anArray.GetSize(); i++) {
			if (strTemp < anArray.GetAt(i)) break;
		}
		anArray.InsertAt(i, strTemp);
	}
}

DWORD CSymbolMap::GetLeftSideCodeHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray)
{
	return GetHitList(m_LeftSideCodeSymbols, aSymbol, aSymbolArray, aHitCountArray);
}

DWORD CSymbolMap::GetRightSideCodeHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray)
{
	return GetHitList(m_RightSideCodeSymbols, aSymbol, aSymbolArray, aHitCountArray);
}

DWORD CSymbolMap::GetLeftSideDataHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray)
{
	return GetHitList(m_LeftSideDataSymbols, aSymbol, aSymbolArray, aHitCountArray);
}

DWORD CSymbolMap::GetRightSideDataHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray)
{
	return GetHitList(m_RightSideDataSymbols, aSymbol, aSymbolArray, aHitCountArray);
}

DWORD CSymbolMap::GetHitList(CMap<CString, LPCTSTR, CStringArray*, CStringArray*> &mapSymbolArrays,
								LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray)
{
	CStringArray *pArray;
	CMap<CString, LPCTSTR, DWORD, DWORD> mapSymbols;
	int i;
	CString strTemp;
	POSITION pos;
	DWORD nTemp;
	DWORD nTotal = 0;

	aSymbolArray.RemoveAll();
	aHitCountArray.RemoveAll();

	if (mapSymbolArrays.Lookup(aSymbol, pArray)) {
		if (pArray) {
			for (i=0; i<pArray->GetSize(); i++) {
				strTemp = pArray->GetAt(i);
				if (mapSymbols.Lookup(strTemp, nTemp)) {
					mapSymbols.SetAt(strTemp, nTemp+1);
				} else {
					mapSymbols.SetAt(strTemp, 1);
				}
			}

			pos = mapSymbols.GetStartPosition();
			while (pos) {
				mapSymbols.GetNextAssoc(pos, strTemp, nTemp);

				for (i=0; i<aHitCountArray.GetSize(); i++) {
					if (nTemp > aHitCountArray.GetAt(i)) break;
					if (nTemp == aHitCountArray.GetAt(i)) {
						if (aSymbolArray.GetAt(i).IsEmpty()) break;
						if ((strTemp < aSymbolArray.GetAt(i)) &&
							(!strTemp.IsEmpty())) break;
					}
				}
				aSymbolArray.InsertAt(i, strTemp);
				aHitCountArray.InsertAt(i, nTemp);
			}

			nTotal = pArray->GetSize();
		}
	}

	return nTotal;
}

/*
void CSymbolMap::SortStringArray(CStringArray &aStringArray)
{
	// Sort an array of strings.  Here, we'll just use bubble sorting
	//	as the number of string entries should be relatively small:
	CString strTemp;
	int i;
	int j;

	for (i=0; i<aStringArray.GetSize()-1; i++) {
		for (j=i+1; j<aStringArray.GetSize(); j++) {
			if (aStringArray.GetAt(i).Compare(aStringArray.GetAt(j)) > 0) {
				strTemp = aStringArray.GetAt(j);
				aStringArray.SetAt(j, aStringArray.GetAt(i));
				aStringArray.SetAt(i, strTemp);
			}
		}
	}
}
*/

/*
void CSymbolMap::SortStringDWordArray(CStringArray &aStringArray, CDWordArray &aDWordArray)
{
	// Sort an array of strings along with an array of numbers.  Since the numbers
	//	are "hit counts", we want them to have precedence in the sort, so we will
	//	sort but numbers and then by string.  We'll just use bubble sorting
	//	as the number of entries should be relatively small:
	CString strTemp;
	DWORD nTemp;
	int i;
	int j;

	ASSERT(aStringArray.GetSize() == aDWordArray.GetSize());	// The two arrays must have same number of elements!

	for (i=0; i<aStringArray.GetSize()-1; i++) {
		for (j=i+1; j<aStringArray.GetSize(); j++) {
			if ((aDWordArray.GetAt(i) < aDWordArray.GetAt(j)) ||
				((aDWordArray.GetAt(i) == aDWordArray.GetAt(j)) && 
				 ((aStringArray.GetAt(i).Compare(aStringArray.GetAt(j)) > 0) || (aStringArray.GetAt(i).IsEmpty())))) {
				strTemp = aStringArray.GetAt(j);
				aStringArray.SetAt(j, aStringArray.GetAt(i));
				aStringArray.SetAt(i, strTemp);
				nTemp = aDWordArray.GetAt(j);
				aDWordArray.SetAt(j, aDWordArray.GetAt(i));
				aDWordArray.SetAt(i, nTemp);
			}
		}
	}
}
*/

void CSymbolMap::AddLeftSideCodeSymbol(LPCTSTR aLeftSymbol, LPCTSTR aRightSymbol)
{
	CStringArray *pArray;

	if (m_LeftSideCodeSymbols.Lookup(aLeftSymbol, pArray)) {
		if (pArray == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return;
		}
	} else {
		pArray = new CStringArray;
		if (pArray == NULL) AfxThrowMemoryException();
		m_LeftSideCodeSymbols.SetAt(aLeftSymbol, pArray);
	}
	ASSERT(pArray != NULL);
	pArray->Add(aRightSymbol);
}

void CSymbolMap::AddRightSideCodeSymbol(LPCTSTR aRightSymbol, LPCTSTR aLeftSymbol)
{
	CStringArray *pArray;

	if (m_RightSideCodeSymbols.Lookup(aRightSymbol, pArray)) {
		if (pArray == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return;
		}
	} else {
		pArray = new CStringArray;
		if (pArray == NULL) AfxThrowMemoryException();
		m_RightSideCodeSymbols.SetAt(aRightSymbol, pArray);
	}
	ASSERT(pArray != NULL);
	pArray->Add(aLeftSymbol);
}

void CSymbolMap::AddLeftSideDataSymbol(LPCTSTR aLeftSymbol, LPCTSTR aRightSymbol)
{
	CStringArray *pArray;

	if (m_LeftSideDataSymbols.Lookup(aLeftSymbol, pArray)) {
		if (pArray == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return;
		}
	} else {
		pArray = new CStringArray;
		if (pArray == NULL) AfxThrowMemoryException();
		m_LeftSideDataSymbols.SetAt(aLeftSymbol, pArray);
	}
	ASSERT(pArray != NULL);
	pArray->Add(aRightSymbol);
}

void CSymbolMap::AddRightSideDataSymbol(LPCTSTR aRightSymbol, LPCTSTR aLeftSymbol)
{
	CStringArray *pArray;

	if (m_RightSideDataSymbols.Lookup(aRightSymbol, pArray)) {
		if (pArray == NULL) {
			ASSERT(FALSE);			// We should never encounter a null entry -- check adding!
			return;
		}
	} else {
		pArray = new CStringArray;
		if (pArray == NULL) AfxThrowMemoryException();
		m_RightSideDataSymbols.SetAt(aRightSymbol, pArray);
	}
	ASSERT(pArray != NULL);
	pArray->Add(aLeftSymbol);
}

<file_sep>/programs/funcanal/FuncView/ChildFrm4.cpp
// ChildFrm4.cpp : implementation file
//
// Frame Window for the Output Views
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm4.cpp,v $
// Revision 1.1  2003/09/13 05:45:34  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "ChildFrm4.h"

#include "OutputView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChildFrame4

IMPLEMENT_DYNCREATE(CChildFrame4, CChildFrameBase)

CChildFrame4::CChildFrame4()
{
	m_pOutputView = NULL;
}

CChildFrame4::~CChildFrame4()
{
}


BEGIN_MESSAGE_MAP(CChildFrame4, CChildFrameBase)
	//{{AFX_MSG_MAP(CChildFrame4)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildFrame4 message handlers

BOOL CChildFrame4::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	ASSERT(pContext != NULL);

	pContext->m_pNewViewClass = RUNTIME_CLASS(COutputView);

	m_pOutputView = (COutputView *)CreateView(pContext, AFX_IDW_PANE_FIRST);
	if (m_pOutputView == NULL) return FALSE;

	return TRUE;

//	return CChildFrameBase::OnCreateClient(lpcs, pContext);
}

<file_sep>/programs/funcanal/FuncView/ChildFrm2.cpp
// ChildFrm2.cpp : implementation file
//
// Frame Window for the Function Diff Views
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm2.cpp,v $
// Revision 1.1  2003/09/13 05:45:32  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "ChildFrm2.h"

#include "FuncListView.h"
#include "FuncDiffEditView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static UINT indicators[] =
{
	ID_SEPARATOR,           // status line indicator
	ID_INDICATOR_MATCH_PERCENT,
};

/////////////////////////////////////////////////////////////////////////////
// CChildFrame2

IMPLEMENT_DYNCREATE(CChildFrame2, CChildFrameBase)

CChildFrame2::CChildFrame2()
{
	m_pLeftFuncList = NULL;
	m_pRightFuncList = NULL;
	m_pDiffView = NULL;
}

CChildFrame2::~CChildFrame2()
{
}

BEGIN_MESSAGE_MAP(CChildFrame2, CChildFrameBase)
	//{{AFX_MSG_MAP(CChildFrame2)
	ON_WM_CREATE()
	ON_COMMAND(ID_SYMBOLS_ADD, OnSymbolsAdd)
	ON_UPDATE_COMMAND_UI(ID_SYMBOLS_ADD, OnUpdateSymbolsAdd)
	//}}AFX_MSG_MAP
	ON_UPDATE_COMMAND_UI(ID_INDICATOR_MATCH_PERCENT, OnUpdateMatchPercent)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildFrame2 message handlers

BOOL CChildFrame2::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	if (!m_wndSplitter.CreateStatic(this, 1, 3)) return FALSE;

	if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CFuncListView), CSize(230, 0), pContext)) return FALSE;
	if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CFuncListView), CSize(230, 0), pContext)) return FALSE;
	if (!m_wndSplitter.CreateView(0, 2, RUNTIME_CLASS(CFuncDiffEditView), CSize(300, 0), pContext)) return FALSE;

	m_pLeftFuncList = (CFuncListView *)m_wndSplitter.GetPane(0, 0);
	m_pRightFuncList = (CFuncListView *)m_wndSplitter.GetPane(0, 1);
	m_pDiffView = (CFuncDiffEditView *)m_wndSplitter.GetPane(0, 2);

	return TRUE;

//	return CChildFrameBase::OnCreateClient(lpcs, pContext);
}

int CChildFrame2::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CChildFrameBase::OnCreate(lpCreateStruct) == -1)
		return -1;

	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}

	return 0;
}

void CChildFrame2::OnUpdateMatchPercent(CCmdUI* pCmdUI)
{
	if (m_pDiffView == NULL) {
		pCmdUI->SetText("");
	} else {
		pCmdUI->SetText(m_pDiffView->m_strMatchPercentage);
	}
}

void CChildFrame2::OnSymbolsAdd() 
{
	// Pass on to diff view to handle:
	if (m_pDiffView) m_pDiffView->OnSymbolsAdd();
}

void CChildFrame2::OnUpdateSymbolsAdd(CCmdUI* pCmdUI) 
{
	// Pass on to diff view to handle:
	if (m_pDiffView) {
		m_pDiffView->OnUpdateSymbolsAdd(pCmdUI);
	} else {
		pCmdUI->Enable(FALSE);
	}
}

<file_sep>/programs/funcanal/FuncView/ChildFrm2.h
// ChildFrm2.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm2.h,v $
// Revision 1.1  2003/09/13 05:45:33  dewhisna
// Initial Revision
//
//

#if !defined(AFX_CHILDFRM2_H__31E158BD_BFD8_4AB8_B28B_361FE203A9DD__INCLUDED_)
#define AFX_CHILDFRM2_H__31E158BD_BFD8_4AB8_B28B_361FE203A9DD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ChildFrmBase.h"

class CFuncListView;
class CFuncDiffEditView;

/////////////////////////////////////////////////////////////////////////////
// CChildFrame2 frame

class CChildFrame2 : public CChildFrameBase
{
	DECLARE_DYNCREATE(CChildFrame2)
protected:
	CChildFrame2();           // protected constructor used by dynamic creation

// Attributes
public:
	CFuncListView *m_pLeftFuncList;
	CFuncListView *m_pRightFuncList;
	CFuncDiffEditView *m_pDiffView;

protected:
	CSplitterWnd m_wndSplitter;
	CStatusBar  m_wndStatusBar;


// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CChildFrame2)
	protected:
	virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CChildFrame2();

	// Generated message map functions
	//{{AFX_MSG(CChildFrame2)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnSymbolsAdd();
	afx_msg void OnUpdateSymbolsAdd(CCmdUI* pCmdUI);
	//}}AFX_MSG
	afx_msg void OnUpdateMatchPercent(CCmdUI* pCmdUI);

	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM2_H__31E158BD_BFD8_4AB8_B28B_361FE203A9DD__INCLUDED_)
<file_sep>/programs/m6811dis/gdc.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

//
//	GDC.CPP	-- Implementation for Generic Disassembly Class
//
//	GDC is a generic means for defining a disassembly process that
//	processor independent.  The functions here provide the processor independent
//	part of the code.  These classes should be overriden as appropriate
//	to handle specific processors.
//

#include "gdc.h"
#include "dfc.h"
#include "stringhelp.h"
#include "memclass.h"
#include "errmsgs.h"
#include <ctime>
#include <ctype.h>
#include <iomanip>
#include <sstream>

#include <assert.h>

#define VERSION 0x200				// GDC Version number 2.00

// ----------------------------------------------------------------------------
//	COpcodeEntry
// ----------------------------------------------------------------------------
COpcodeEntry::COpcodeEntry()
{
	m_OpcodeBytes.clear();
	m_Group = 0;
	m_Control = 0;
	m_UserData = 0;
	m_Mnemonic = "<undefined>";
}

COpcodeEntry::COpcodeEntry(int nNumBytes, unsigned char *Bytes, unsigned int nGroup, unsigned int nControl, const std::string & szMnemonic, unsigned int nUserData)
{
	m_OpcodeBytes.clear();
	for (int i=0; i<nNumBytes; ++i) {
		m_OpcodeBytes.push_back(Bytes[i]);
	}
	m_Group = nGroup;
	m_Control = nControl;
	m_UserData = nUserData;
	m_Mnemonic = szMnemonic;
}

COpcodeEntry::COpcodeEntry(const COpcodeEntry& aEntry)
{
	CopyFrom(aEntry);
}

void COpcodeEntry::CopyFrom(const COpcodeEntry& aEntry)
{
	m_OpcodeBytes.clear();
	for (unsigned int i=0; i<aEntry.m_OpcodeBytes.size(); ++i) {
		m_OpcodeBytes.push_back(aEntry.m_OpcodeBytes.at(i));
	}
	m_Group = aEntry.m_Group;
	m_Control = aEntry.m_Control;
	m_UserData = aEntry.m_UserData;
	m_Mnemonic = aEntry.m_Mnemonic;
}

COpcodeEntry &COpcodeEntry::operator=(const COpcodeEntry& aEntry)
{
	CopyFrom(aEntry);
	return *this;
}


// ----------------------------------------------------------------------------
//	COpcodeArray
// ----------------------------------------------------------------------------
COpcodeArray::COpcodeArray()
	:	std::vector<COpcodeEntry>()
{
}

COpcodeArray::~COpcodeArray()
{
}


// ----------------------------------------------------------------------------
//	COpcodeTable
// ----------------------------------------------------------------------------
COpcodeTable::COpcodeTable()
{
}

COpcodeTable::~COpcodeTable()
{
}

void COpcodeTable::AddOpcode(const COpcodeEntry& nOpcode)
{
	if (nOpcode.m_OpcodeBytes.size() == 0) return;	// MUST have an initial byte in the opcode!

	iterator itrArray = find(nOpcode.m_OpcodeBytes.at(0));
	if (itrArray == end()) {
		COpcodeArray anArray;
		anArray.push_back(nOpcode);
		operator [](nOpcode.m_OpcodeBytes.at(0)) = anArray;
	} else {
		itrArray->second.push_back(nOpcode);
	}
}


// ----------------------------------------------------------------------------
//	CDisassembler
// ----------------------------------------------------------------------------

CDisassembler::CDisassembler()
	:	m_ROMMemMap(0, 0, 0),
		m_RAMMemMap(0, 0, 0),
		m_IOMemMap(0, 0, 0)
{
	// Get system time:
	m_StartTime = time(NULL);

	// Set output defaults:
	m_bAddrFlag = false;
	m_bOpcodeFlag = false;
	m_bAsciiFlag = false;
	m_bSpitFlag = false;
	m_bTabsFlag = true;
	m_bAsciiBytesFlag = true;
	m_bDataOpBytesFlag = false;

	m_nMaxNonPrint = 8;
	m_nMaxPrint = 40;
	m_nTabWidth = 4;

	m_nBase = 16;						// See ReadControlFile function before changing these 3 here!
	m_sDefaultDFC = "binary";
	m_sInputFilename = "";

	m_nLoadAddress = 0;
	m_sOutputFilename = "";
	m_sFunctionsFilename = "";
	m_sInputFileList.clear();
	m_sControlFileList.clear();

	// Setup commands to parse:
	ParseCmds["ENTRY"] = 1;
	ParseCmds["LOAD"] = 2;
	ParseCmds["INPUT"] = 3;
	ParseCmds["OUTPUT"] = 4;
	ParseCmds["LABEL"] = 5;
	ParseCmds["ADDRESSES"] = 6;
	ParseCmds["INDIRECT"] = 7;
	ParseCmds["OPCODES"] = 8;
	ParseCmds["OPBYTES"] = 8;
	ParseCmds["ASCII"] = 9;
	ParseCmds["SPIT"] = 10;
	ParseCmds["BASE"] = 11;
	ParseCmds["MAXNONPRINT"] = 12;
	ParseCmds["MAXPRINT"] = 13;
	ParseCmds["DFC"] = 14;
	ParseCmds["TABS"] = 15;
	ParseCmds["TABWIDTH"] = 16;
	ParseCmds["ASCIIBYTES"] = 17;
	ParseCmds["DATAOPBYTES"] = 18;
	ParseCmds["EXITFUNCTION"] = 19;
	ParseCmds["MEMMAP"] = 20;

	ParseCmdsOP1["OFF"] = false;
	ParseCmdsOP1["ON"] = true;
	ParseCmdsOP1["FALSE"] = false;
	ParseCmdsOP1["TRUE"] = true;
	ParseCmdsOP1["NO"] = false;
	ParseCmdsOP1["YES"] = true;

	ParseCmdsOP2["OFF"] = 0;
	ParseCmdsOP2["NONE"] = 0;
	ParseCmdsOP2["0"] = 0;
	ParseCmdsOP2["BIN"] = 2;
	ParseCmdsOP2["BINARY"] = 2;
	ParseCmdsOP2["2"] = 2;
	ParseCmdsOP2["OCT"] = 8;
	ParseCmdsOP2["OCTAL"] = 8;
	ParseCmdsOP2["8"] = 8;
	ParseCmdsOP2["DEC"] = 10;
	ParseCmdsOP2["DECIMAL"] = 10;
	ParseCmdsOP2["10"] = 10;
	ParseCmdsOP2["HEX"] = 16;
	ParseCmdsOP2["HEXADECIMAL"] = 16;
	ParseCmdsOP2["16"] = 16;

	ParseCmdsOP3["CODE"] = 0;
	ParseCmdsOP3["DATA"] = 1;

	ParseCmdsOP4["ROM"] = 0;
	ParseCmdsOP4["RAM"] = 1;
	ParseCmdsOP4["IO"] = 2;

	ParseCmdsOP5["DISASSEMBLY"] = 0;
	ParseCmdsOP5["DISASSEMBLE"] = 0;
	ParseCmdsOP5["DISASSEM"] = 0;
	ParseCmdsOP5["DISASM"] = 0;
	ParseCmdsOP5["DIS"] = 0;
	ParseCmdsOP5["DASM"] = 0;
	ParseCmdsOP5["FUNCTION"] = 1;
	ParseCmdsOP5["FUNCTIONS"] = 1;
	ParseCmdsOP5["FUNC"] = 1;
	ParseCmdsOP5["FUNCT"] = 1;
	ParseCmdsOP5["FUNCTS"] = 1;

	m_Memory = NULL;
	m_nFilesLoaded = 0;
	m_PC = 0;

	LAdrDplyCnt=0;
}

CDisassembler::~CDisassembler()
{
	ParseCmds.clear();
	ParseCmdsOP1.clear();
	ParseCmdsOP2.clear();
	ParseCmdsOP3.clear();
	ParseCmdsOP4.clear();
	ParseCmdsOP5.clear();

	m_sInputFileList.clear();
	m_sControlFileList.clear();

	m_EntryTable.clear();

	m_FunctionsTable.clear();
	m_FuncExitAddresses.clear();

	m_BranchTable.clear();
	m_LabelTable.clear();
	m_LabelRefTable.clear();

	m_CodeIndirectTable.clear();
	m_DataIndirectTable.clear();

	if (m_Memory) {
		delete m_Memory;
		m_Memory = NULL;
	}
}

unsigned int CDisassembler::GetVersionNumber()
{
	return (VERSION << 16);
}

bool CDisassembler::ReadControlFile(ifstreamControlFile& inFile, bool bLastFile, std::ostream *msgFile, std::ostream *errFile, int nStartLineCount)
{
	bool RetVal;

	std::string aLine;
	TStringArray args;
	unsigned int Address;
	unsigned int ResAddress;
	TDWordArray SortedList;
	TMemRange *pMemRange;

	// Note: m_nFilesLoaded must be properly set/reset prior to calling this function
	//		This is typically done in the constructor -- but overrides, etc, doing
	//		preloading of files should properly set it as well.

	//	bLastFile causes this function to report the overall disassembly summary from
	//		control files -- such as "at least one input file" and "output file must
	//		be specified" type error messages and sets any default action that should
	//		be taken with entries, etc.  The reason for the boolean flag is to
	//		allow processing of several control files prior to reporting the summary.
	//		Typically, the last control file processed should be called with a "true"
	//		and all prior control files processed should be called with a "FALSE".

	RetVal = true;

	m_sControlFileList.push_back(inFile.getFilename());

	if (msgFile) {
		(*msgFile) << "Reading and Parsing Control File: \"" << inFile.getFilename() << "\"...\n";
	}

	m_nBase = 16;						// Reset the default base before starting new file.. Therefore, each file has same default!
	m_sDefaultDFC = "binary";			// Reset the default DFC format so every control file starts with same default!
	m_sInputFilename = "";				// Reset the Input Filename so we won't try to reload file from previous control file if this control doesn't specify one

	m_nCtrlLine = nStartLineCount;		// In case several lines were read by outside process, it should pass in correct starting number so we display correct error messages!
	while (inFile.good()) {
		std::getline(inFile, aLine);
		m_nCtrlLine++;
		m_ParseError = "*** Error: Unknown error";
		std::size_t pos = aLine.find(';');
		if (pos != std::string::npos) aLine = aLine.substr(0, pos);		// Trim off comments!
		trim(aLine);
		if (aLine.size() == 0) continue;	// If it is a blank or null line or only a comment, keep going
		args.clear();
		std::string Temp = aLine;
		while (Temp.size()) {
			pos = Temp.find_first_of("\x009\x00a\x00b\x00c\x00d\x020");
			if (pos != std::string::npos) {
				args.push_back(Temp.substr(0, pos));
				Temp = Temp.substr(pos+1);
			} else {
				args.push_back(Temp);
				Temp.clear();
			}
			ltrim(Temp);
		}
		if (args.size() == 0) continue;		// If we don't have any args, get next line (really shouldn't ever have no args here)

		if (ParseControlLine(aLine, args, msgFile, errFile) == false) {		// Go parse it -- either internal or overrides
			if (errFile) {
				(*errFile) << m_ParseError;
				(*errFile) << " in Control File \"" << inFile.getFilename() << "\" line " << m_nCtrlLine << "\n";
			}
		}
	}

	// If a Input File was specified by the control file, then open it and read it here:
	if (!m_sInputFilename.empty()) {
		ReadSourceFile(m_sInputFilename, m_nLoadAddress, m_sDefaultDFC, msgFile, errFile);
	}

	if (bLastFile) {
		if (m_nFilesLoaded == 0) {
			if (errFile) (*errFile) << "*** Error: At least one input file must be specified in the control file(s) and successfully loaded\n";
			RetVal = false;
		}
		if (m_sOutputFilename.empty()) {
			if (errFile) (*errFile) << "*** Error: Disassembly Output file must be specified in the control file(s)\n";
			RetVal = false;
		}
		if ((m_bSpitFlag == false) && (m_EntryTable.size() == 0) && (m_CodeIndirectTable.size() == 0)) {
			if (errFile) (*errFile) << "*** Error: No entry addresses or indirect code vectors have been specified in the control file(s)\n";
			RetVal = false;
		}

		if (RetVal) {
			if (msgFile) {
				(*msgFile) << "\n";
				(*msgFile) << "        " << m_sInputFileList.size() << " Source File"
										<< ((m_sInputFileList.size() != 1) ? "s" : "")
										<< ((m_sInputFileList.size() != 0) ? ":" : "");
				if (m_sInputFileList.size() == 1) {
					(*msgFile) << " " << m_sInputFileList.at(0) << "\n";
				} else {
					for (unsigned int i=0; i<m_sInputFileList.size(); ++i) {
						(*msgFile) << "                " << m_sInputFileList.at(i) << "\n";
					}
				}
				(*msgFile) << "\n";

				if (!m_sOutputFilename.empty()) {
					(*msgFile) << "        Disassembly Output File: " << m_sOutputFilename << "\n\n";
				}

				if (!m_sFunctionsFilename.empty()) {
					(*msgFile) << "        Functions Output File: " << m_sFunctionsFilename << "\n\n";
				}

				(*msgFile) << "        Memory Mappings:\n";
				(*msgFile) << "            ROM Memory Map:";
				if (m_ROMMemMap.IsNullRange()) {
					(*msgFile) << " <Not Defined>\n";
				} else {
					(*msgFile) << "\n";
					pMemRange = &m_ROMMemMap;
					while (pMemRange) {
						(*msgFile) << "                "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
									<< std::nouppercase << std::setbase(0) << " - "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
									<< std::nouppercase << std::setbase(0) << "  (Size: "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
									<< std::nouppercase << std::setbase(0) << ")\n";
						pMemRange = pMemRange->GetNext();
					}
				}
				(*msgFile) << "            RAM Memory Map:";
				if (m_RAMMemMap.IsNullRange()) {
					(*msgFile) << " <Not Defined>\n";
				} else {
					(*msgFile) << "\n";
					pMemRange = &m_RAMMemMap;
					while (pMemRange) {
						(*msgFile) << "                "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
									<< std::nouppercase << std::setbase(0) << " - "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
									<< std::nouppercase << std::setbase(0) << "  (Size: "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
									<< std::nouppercase << std::setbase(0) << ")\n";
						pMemRange = pMemRange->GetNext();
					}
				}
				(*msgFile) << "             IO Memory Map:";
				if (m_IOMemMap.IsNullRange()) {
					(*msgFile) << " <Not Defined>\n";
				} else {
					(*msgFile) << "\n";
					pMemRange = &m_IOMemMap;
					while (pMemRange) {
						(*msgFile) << "                "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
									<< std::nouppercase << std::setbase(0) << " - "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
									<< std::nouppercase << std::setbase(0) << "  (Size: "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
									<< std::nouppercase << std::setbase(0) << ")\n";
						pMemRange = pMemRange->GetNext();
					}
				}
				(*msgFile) << "\n";
				(*msgFile) << "        " << m_EntryTable.size() << " Entry Point"
											<< ((m_EntryTable.size() != 1) ? "s" : "")
											<< ((m_EntryTable.size() != 0) ? ":" : "")
											<< "\n";
			}
			SortedList.clear();
			for (TAddressMap::const_iterator itrEntry = m_EntryTable.begin(); itrEntry != m_EntryTable.end(); ++itrEntry) {
				TDWordArray::iterator itrSorted;
				for (itrSorted = SortedList.begin(); itrSorted != SortedList.end(); ++itrSorted) {
					if (itrEntry->first <= *itrSorted) {
						break;
					}
				}
				SortedList.insert(itrSorted, itrEntry->first);
			}
			for (unsigned int i=0; i<SortedList.size(); ++i) {
				if (msgFile) {
					(*msgFile) << "                "
								<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << SortedList.at(i)
								<< std::nouppercase << std::setbase(0) << "\n";
				}
				if (IsAddressLoaded(SortedList.at(i), 1) == false) {
					if (errFile) {
						(*errFile) << "    *** Warning: Entry Point Address "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << SortedList.at(i)
									<< std::nouppercase << std::setbase(0) << " is outside of loaded source file(s)...\n";
					}
				}
			}

			if (msgFile) {
				(*msgFile) << "\n";
				(*msgFile) << "        " << m_FuncExitAddresses.size()
							<< " Exit Function"
							<< ((m_FuncExitAddresses.size() != 1) ? "s" : "")
							<< " Defined"
							<< ((m_FuncExitAddresses.size() != 0) ? ":" : "")
							<< "\n";
			}
			SortedList.clear();
			for (TAddressMap::const_iterator itrEntry = m_FuncExitAddresses.begin(); itrEntry != m_FuncExitAddresses.end(); ++itrEntry) {
				TDWordArray::iterator itrSorted;
				for (itrSorted = SortedList.begin(); itrSorted != SortedList.end(); ++itrSorted) {
					if (itrEntry->first <= *itrSorted) {
						break;
					}
				}
				SortedList.insert(itrSorted, itrEntry->first);
			}
			for (unsigned int i=0; i<SortedList.size(); ++i) {
				if (msgFile) {
					(*msgFile) << "                "
								<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << SortedList.at(i)
								<< std::nouppercase << std::setbase(0) << "\n";
				}
				if (IsAddressLoaded(SortedList.at(i), 1) == false) {
					if (errFile) {
						(*errFile) << "    *** Warning: Exit Function Address "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << SortedList.at(i)
									<< std::nouppercase << std::setbase(0) << " is outside of loaded source file(s)...\n";
					}
				}
			}

			if (msgFile) {
				(*msgFile) << "\n";
				(*msgFile) << "        " << m_LabelTable.size()
							<< " Unique Label"
							<< ((m_LabelTable.size() != 1) ? "s" : "")
							<< " Defined"
							<< ((m_LabelTable.size() != 0) ? ":" : "")
							<< "\n";
				SortedList.clear();
				for (TLabelTableMap::const_iterator itrEntry = m_LabelTable.begin(); itrEntry != m_LabelTable.end(); ++itrEntry) {
					TDWordArray::iterator itrSorted;
					for (itrSorted = SortedList.begin(); itrSorted != SortedList.end(); ++itrSorted) {
						if (itrEntry->first <= *itrSorted) {
							break;
						}
					}
					SortedList.insert(itrSorted, itrEntry->first);
				}
				for (unsigned int i=0; i<SortedList.size(); ++i) {
					TLabelTableMap::const_iterator itrLabelTable = m_LabelTable.find(SortedList.at(i));
					assert(itrLabelTable != m_LabelTable.end());
					(*msgFile) << "                "
								<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << SortedList.at(i)
								<< std::nouppercase << std::setbase(0) << "=";
					for (unsigned int j=0; j<itrLabelTable->second.size(); ++j) {
						if (j != 0) (*msgFile) << ",";
						(*msgFile) << (itrLabelTable->second.at(j));
					}
					(*msgFile) << "\n";
				}
				(*msgFile) << "\n";

				if (m_bAddrFlag) (*msgFile) << "Writing program counter addresses to disassembly file.\n";
				if (m_bOpcodeFlag) (*msgFile) << "Writing opcode byte values to disassembly file.\n";
				if (m_bAsciiFlag) (*msgFile) << "Writing printable data as ASCII in disassembly file.\n";
				if (m_bSpitFlag) (*msgFile) << "Performing a code-dump (spit) disassembly instead of code-seeking.\n";
				if (m_bTabsFlag) {
					(*msgFile) << "Using tab characters in disassembly file.  Tab width set at: " << m_nTabWidth << "\n";
				}
				if (m_bAsciiBytesFlag) (*msgFile) << "Writing byte value comments for ASCII data in disassembly file.\n";
				if ((m_bOpcodeFlag) && (m_bDataOpBytesFlag)) (*msgFile) << "Writing OpBytes for data in disassembly file\n";
				(*msgFile) << "\n";
			}


		// Ok, now we resolve the indirect tables...  This process should create the indirect
		//		label name from the resolved address if the corresponding string in the hash table is "".
		//		This process requires the purely virtual ResolveIndirect function from overrides...
			if (msgFile) (*msgFile) << "Compiling Indirect Code (branch) Table as specified in Control File...\n";
			SortedList.clear();
			for (TAddressLabelMap::const_iterator itrEntry = m_CodeIndirectTable.begin(); itrEntry != m_CodeIndirectTable.end(); ++itrEntry) {
				TDWordArray::iterator itrSorted;
				for (itrSorted = SortedList.begin(); itrSorted != SortedList.end(); ++itrSorted) {
					if (itrEntry->first <= *itrSorted) {
						break;
					}
				}
				SortedList.insert(itrSorted, itrEntry->first);
			}

			if (msgFile) {
				(*msgFile) << "        " << SortedList.size() << " Indirect Code Vector"
							<< ((SortedList.size() != 1) ? "s" : "")
							<< ((SortedList.size() != 0) ? ":" : "")
							<< "\n";
			}
			for (unsigned int i=0; i<SortedList.size(); ++i) {
				Address = SortedList.at(i);
				TAddressLabelMap::const_iterator itrTable = m_CodeIndirectTable.find(Address);
				assert(itrTable != m_CodeIndirectTable.end());
				if (msgFile) {
					(*msgFile) << "                ["
								<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << Address
								<< std::nouppercase << std::setbase(0) << "] -> ";
				}
				if (ResolveIndirect(Address, ResAddress, 0) == false) {
					if (msgFile) (*msgFile) << "ERROR\n";
					if (errFile) {
						(*errFile) << "    *** Warning: Vector Address "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << Address
									<< std::nouppercase << std::setbase(0) << " is outside of loaded source file(s)...\n";
						(*errFile) << "                    Or the vector location conflicted with other analyzed areas.\n";
					}
				} else {
					if (msgFile) {
						(*msgFile) << GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << ResAddress
									<< std::nouppercase << std::setbase(0);
					}
					AddLabel(ResAddress, false, 0, itrTable->second);	// Add label for resolved name.  If NULL, add it so later we can resolve Lxxxx from it.
					m_FunctionsTable[ResAddress] = FUNCF_INDIRECT;		// Resolved code indirects are also considered start-of functions
					if (AddBranch(ResAddress, true, Address) == false) {
						if (errFile) {
							(*errFile) << "    *** Warning: Indirect Address ["
										<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << Address
										<< std::nouppercase << std::setbase(0) << "] -> "
										<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << ResAddress
										<< std::nouppercase << std::setbase(0) << " is outside of loaded source file(s)...\n";
						}
						if ((msgFile) && (msgFile != errFile)) {
							(*msgFile) << "\n";
						}
					} else {
						if (msgFile) {
							(*msgFile) << "\n";
						}
					}
				}
			}
			if (msgFile) (*msgFile) << "\n";
			// Now, repeat for Data indirects:
			if (msgFile) (*msgFile) << "Compiling Indirect Data Table as specified in Control File...\n";
			SortedList.clear();
			for (TAddressLabelMap::const_iterator itrEntry = m_DataIndirectTable.begin(); itrEntry != m_DataIndirectTable.end(); ++itrEntry) {
				TDWordArray::iterator itrSorted;
				for (itrSorted = SortedList.begin(); itrSorted != SortedList.end(); ++itrSorted) {
					if (itrEntry->first <= *itrSorted) {
						break;
					}
				}
				SortedList.insert(itrSorted, itrEntry->first);
			}

			if (msgFile) {
				(*msgFile) << "        " << SortedList.size() << " Indirect Data Vector"
							<< ((SortedList.size() != 1) ? "s" : "")
							<< ((SortedList.size() != 0) ? ":" : "")
							<< "\n";
			}
			for (unsigned int i=0; i<SortedList.size(); ++i) {
				Address = SortedList.at(i);
				TAddressLabelMap::const_iterator itrTable = m_DataIndirectTable.find(Address);
				assert(itrTable != m_DataIndirectTable.end());
				if (msgFile) {
					(*msgFile) << "                ["
								<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << Address
								<< std::nouppercase << std::setbase(0) << "] -> ";
				}
				if (ResolveIndirect(Address, ResAddress, 1) == false) {
					if (msgFile) (*msgFile) << "ERROR\n";
					if (errFile) {
						(*errFile) << "    *** Warning: Vector Address "
									<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << Address
									<< std::nouppercase << std::setbase(0) << " is outside of loaded source file(s)...\n";
						(*errFile) << "                    Or the vector location conflicted with other analyzed areas.\n";
					}
				} else {
					if (msgFile) {
						(*msgFile) << GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << ResAddress
									<< std::nouppercase << std::setbase(0) << "\n";
					}
					AddLabel(ResAddress, true, Address, itrTable->second);		// Add label for resolved name.  If NULL, add it so later we can resolve Lxxxx from it.
				}
			}
			if (msgFile) (*msgFile) << "\n";
		}
	}

	return RetVal;
}

bool CDisassembler::ParseControlLine(const std::string & /* szLine */, TStringArray& argv, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal;
	std::string	Cmd;
	unsigned int CmdIndex;
	unsigned int Address;
	unsigned int Size;
	std::string TempStr;
	std::string DfcLibrary;
	std::string FileName;
	unsigned int TempWord;
	unsigned int TempDWord;
	int ArgError;
	bool TempFlag;
	bool TempFlag2;

	assert(argv.size() != 0);

	if (argv.size() == 0) return false;

	RetVal = true;
	ArgError = 0;

	Cmd = argv[0];
	makeUpper(Cmd);

	CmdIndex = -1;
	TParseCmdMap::const_iterator itrParse = ParseCmds.find(Cmd);
	if (itrParse != ParseCmds.end()) CmdIndex = itrParse->second;
	switch (CmdIndex) {
		case 1:		// ENTRY <addr> [<name>]
			if (argv.size() < 2) {
				ArgError = 1;
				break;
			}
			if (argv.size() > 3) {
				ArgError = 2;
				break;
			}
			if (argv.size() == 3) {
				if (!ValidateLabelName(argv[2])) {
					ArgError = 3;
					break;
				}
			}
			Address = strtoul(argv[1].c_str(), NULL, m_nBase);
			if (m_EntryTable.find(Address) != m_EntryTable.end()) {
				RetVal = false;
				m_ParseError = "*** Warning: Duplicate entry address";
			}
			m_EntryTable[Address] = true;	// Add an entry to the entry table
			m_FunctionsTable[Address] = FUNCF_ENTRY;	// Entries are also considered start-of functions
			if (argv.size() == 3) {
				if (AddLabel(Address, false, 0, argv[2]) == false) {
					RetVal = false;
					m_ParseError = "*** Warning: Duplicate label";
				}
			}
			break;
		case 2:		// LOAD <addr> | <addr> <filename> [<library>]
		{
			if (argv.size() == 2) {
				m_nLoadAddress = strtoul(argv[1].c_str(), NULL, m_nBase);
				break;
			}
			if (argv.size() < 3) {
				ArgError = 1;
				break;
			}
			if (argv.size() > 4) {
				ArgError = 2;
				break;
			}
			Address = strtoul(argv[1].c_str(), NULL, m_nBase);
			if (argv.size() == 4) {
				DfcLibrary = argv[3];
			} else {
				DfcLibrary = m_sDefaultDFC;
			}
			FileName = argv[2];

			ReadSourceFile(FileName, Address, DfcLibrary, msgFile, errFile);
			// We don't set RetVal to FALSE here if there is an error on ReadSource,
			//	because errors have already been printed and are not in ParseError...
			break;
		}
		case 3:		// INPUT <filename>
			if (argv.size() != 2) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}
			if (!m_sInputFilename.empty()) {
				RetVal = false;
				m_ParseError = "*** Warning: Input filename already defined";
			}
			m_sInputFilename = argv[1];
			break;
		case 4:		// OUTPUT [DISASSEMBLY | FUNCTIONS] <filename>
			if ((argv.size() != 2) && (argv.size() != 3)) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}
			TempFlag = false;		// TempFlag = FALSE if type not specified on line, true if it is
			if (argv.size() == 2) {		// If type isn't specified, assume DISASSEMBLY
				TempWord = 0;
			} else {
				TempFlag = true;
				TempStr = argv[1];
				makeUpper(TempStr);
				itrParse = ParseCmdsOP5.find(TempStr);
				if (itrParse == ParseCmdsOP5.end()) {
					ArgError = 3;
					break;
				} else {
					TempWord = itrParse->second;
				}
			}
			switch (TempWord) {
				case 0:				// DISASSEMBLY
					if (!m_sOutputFilename.empty()) {
						RetVal = false;
						m_ParseError = "*** Warning: Disassembly Output filename already defined";
					}
					m_sOutputFilename = argv[((TempFlag) ? 2 : 1)];
					break;
				case 1:				// FUNCTIONS
					if (!m_sFunctionsFilename.empty()) {
						RetVal = false;
						m_ParseError = "*** Warning: Functions Output filename already defined";
					}
					m_sFunctionsFilename = argv[((TempFlag) ? 2 : 1)];
					break;
			}
			break;
		case 5:		// LABEL <addr> <name>
			if (argv.size() != 3) {
				ArgError = (argv.size() < 3) ? 1 : 2;
				break;
			}
			if (!ValidateLabelName(argv[2])) {
				ArgError = 3;
				break;
			}
			Address = strtoul(argv[1].c_str(), NULL, m_nBase);
			if (AddLabel(Address, false, 0, argv[2]) == false) {
				RetVal = false;
				m_ParseError = "*** Warning: Duplicate label";
			}
			break;
		case 6:		// ADDRESSES [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bAddrFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bAddrFlag = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 7:		// INDIRECT [CODE | DATA] <addr> [<name>]
			if ((argv.size() != 2) && (argv.size() != 3) && (argv.size() != 4)) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}

			TempFlag = false;		// TempFlag = FALSE if CODE/DATA not specified on line, true if it is
			TempFlag2 = false;		// TempFlag2 = FALSE if <name> not specified on line, true if it is
			if (argv.size() == 2) {		// If Code or Data isn't specified, assume code
				TempWord = 0;
			} else {
				TempStr = argv[1];
				makeUpper(TempStr);
				itrParse = ParseCmdsOP3.find(TempStr);
				if (itrParse == ParseCmdsOP3.end()) {
					if (argv.size() == 4) {			// If all args was specified, error out if not valid
						ArgError = 3;
						break;
					} else {					// If here, we assume we have <addr> and <name> since we are one arg short
						TempWord = 0;			// Assume Code since it isn't specified
						TempFlag2 = true;		// And we do have a <name>
					}
				} else {
					TempWord = itrParse->second;
					TempFlag = true;
					if (argv.size() == 4) {			// If all args was specified, we have valid everything
						TempFlag2 = true;
					}
				}
			}

			// From the following point to the end of this case, TempStr = the Indirect <name>
			//		If not specified, we set the name to "" so the Resolution function will
			//		create it from the resolved address...
			if (TempFlag2) {
				TempStr = argv[2 + ((TempFlag) ? 1 : 0)];
				if (!ValidateLabelName(TempStr)) {
					ArgError = 3;
					break;
				}
			} else {
				TempStr = "";
			}
			Address = strtoul(argv[1 + ((TempFlag) ? 1 : 0)].c_str(), NULL, m_nBase);
			switch (TempWord) {
				case 0:
					if ((m_CodeIndirectTable.find(Address) != m_CodeIndirectTable.end()) ||
						(m_DataIndirectTable.find(Address) != m_DataIndirectTable.end())) {
						RetVal = false;
						m_ParseError = "*** Warning: Duplicate indirect";
					}
					m_CodeIndirectTable[Address] = TempStr;	// Add a label to the code indirect table
					break;
				case 1:
					if ((m_DataIndirectTable.find(Address) != m_DataIndirectTable.end()) ||
						(m_CodeIndirectTable.find(Address) != m_CodeIndirectTable.end())) {
						RetVal = false;
						m_ParseError = "*** Warning: Duplicate indirect";
					}
					m_DataIndirectTable[Address] = TempStr;	// Add a label to the data indirect table
					break;
			}
			break;
		case 8:		// OPCODES [ON | OFF | TRUE | FALSE | YES | NO]
					// OPBYTES [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bOpcodeFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bOpcodeFlag = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 9:		// ASCII [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bAsciiFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bAsciiFlag = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 10:	// SPIT [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bSpitFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bSpitFlag = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 11:	// BASE [OFF | BIN | OCT | DEC | HEX]
			if (argv.size() < 2) {
				m_nBase = 0;		// Default is OFF
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP2.find(TempStr);
			if (itrParse != ParseCmdsOP2.end()) {
				m_nBase = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 12:	// MAXNONPRINT <value>
			if (argv.size() != 2) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}
			m_nMaxNonPrint = strtoul(argv[1].c_str(), NULL, m_nBase);
			break;
		case 13:	// MAXPRINT <value>
			if (argv.size() != 2) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}
			m_nMaxPrint = strtoul(argv[1].c_str(), NULL, m_nBase);
			break;
		case 14:	// DFC <library>
			if (argv.size() != 2) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}
			m_sDefaultDFC = argv[1];
			break;
		case 15:	// TABS [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bTabsFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bTabsFlag = itrParse->second;
			} else{
				ArgError = 3;
			}
			break;
		case 16:	// TABWIDTH <value>
			if (argv.size() != 2) {
				ArgError = (argv.size() < 2) ? 1 : 2;
				break;
			}
			m_nTabWidth = strtoul(argv[1].c_str(), NULL, m_nBase);
			break;
		case 17:	// ASCIIBYTES [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bAsciiBytesFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bAsciiBytesFlag = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 18:	// DATAOPBYTES [ON | OFF | TRUE | FALSE | YES | NO]
			if (argv.size() < 2) {
				m_bDataOpBytesFlag = true;		// Default is ON
				break;
			}
			if (argv.size() > 2) {
				ArgError = 2;
				break;
			}
			TempStr = argv[1];
			makeUpper(TempStr);
			itrParse = ParseCmdsOP1.find(TempStr);
			if (itrParse != ParseCmdsOP1.end()) {
				m_bDataOpBytesFlag = itrParse->second;
			} else {
				ArgError = 3;
			}
			break;
		case 19:	// EXITFUNCTION <addr> [<name>]
			if (argv.size() < 2) {
				ArgError = 1;
				break;
			}
			if (argv.size() > 3) {
				ArgError = 2;
				break;
			}
			if (argv.size() == 3) {
				if (!ValidateLabelName(argv[2])) {
					ArgError = 3;
					break;
				}
			}
			Address = strtoul(argv[1].c_str(), NULL, m_nBase);
			if (m_FuncExitAddresses.find(Address) != m_FuncExitAddresses.end()) {
				RetVal = false;
				m_ParseError = "*** Warning: Duplicate function exit address";
			}
			m_FunctionsTable[Address] = FUNCF_ENTRY;	// Exit Function Entry points are also considered start-of functions
			m_FuncExitAddresses[Address] = true;		// Add function exit entry
			if (argv.size() == 3) {
				if (AddLabel(Address, false, 0, argv[2]) == false) {
					RetVal = false;
					m_ParseError = "*** Warning: Duplicate label";
				}
			}
			break;
		case 20:	// MEMMAP [ROM | RAM | IO] <addr> <size>
			if ((argv.size() != 3) && (argv.size() != 4)) {
				ArgError = (argv.size() < 3) ? 1 : 2;
				break;
			}

			TempFlag = false;		// TempFlag = FALSE if ROM/RAM/IO not specified on line, true if it is
			if (argv.size() == 3) {		// If ROM/RAM/IO not specified on line, assume ROM
				TempWord = 0;
			} else {
				TempStr = argv[1];
				makeUpper(TempStr);
				itrParse = ParseCmdsOP4.find(TempStr);
				if (itrParse != ParseCmdsOP4.end()) {
					TempWord = itrParse->second;
					TempFlag = true;		// If specified and valid, set flag
				} else {
					ArgError = 3;			// Error out if type not valid but specified
					break;
				}
			}

			// Get address and size specified:
			Address = strtoul(argv[1 + ((TempFlag) ? 1 : 0)].c_str(), NULL, m_nBase);
			Size = strtoul(argv[2 + ((TempFlag) ? 1 : 0)].c_str(), NULL, m_nBase);

			switch (TempWord) {
				case 0:		// ROM
					m_ROMMemMap.AddRange(Address, Size, 0);
					m_ROMMemMap.Compact();
					m_ROMMemMap.RemoveOverlaps();
					m_ROMMemMap.Sort();
					for (TempDWord = Address; ((TempDWord < (Address + Size)) && (RetVal)); TempDWord++) {
						if (m_RAMMemMap.AddressInRange(TempDWord)) {
							RetVal = false;
							m_ParseError = "*** Warning: Specified ROM Mapping conflicts with RAM Mapping";
						} else {
							if (m_IOMemMap.AddressInRange(TempDWord)) {
								RetVal = false;
								m_ParseError = "*** Warning: Specified ROM Mapping conflicts with IO Mapping";
							}
						}
					}
					break;
				case 1:		// RAM
					m_RAMMemMap.AddRange(Address, Size, 0);
					m_RAMMemMap.Compact();
					m_RAMMemMap.RemoveOverlaps();
					m_RAMMemMap.Sort();
					for (TempDWord = Address; ((TempDWord < (Address + Size)) && (RetVal)); TempDWord++) {
						if (m_ROMMemMap.AddressInRange(TempDWord)) {
							RetVal = false;
							m_ParseError = "*** Warning: Specified RAM Mapping conflicts with ROM Mapping";
						} else {
							if (m_IOMemMap.AddressInRange(TempDWord)) {
								RetVal = false;
								m_ParseError = "*** Warning: Specified RAM Mapping conflicts with IO Mapping";
							}
						}
					}
					break;
				case 2:		// IO
					m_IOMemMap.AddRange(Address, Size, 0);
					m_IOMemMap.Compact();
					m_IOMemMap.RemoveOverlaps();
					m_IOMemMap.Sort();
					for (TempDWord = Address; ((TempDWord < (Address + Size)) && (RetVal)); TempDWord++) {
						if (m_ROMMemMap.AddressInRange(TempDWord)) {
							RetVal = false;
							m_ParseError = "*** Warning: Specified IO Mapping conflicts with ROM Mapping";
						} else {
							if (m_RAMMemMap.AddressInRange(TempDWord)) {
								RetVal = false;
								m_ParseError = "*** Warning: Specified IO Mapping conflicts with RAM Mapping";
							}
						}
					}
					break;
			}
			break;
		default:
			m_ParseError = "*** Error: Unknown command";
			return false;
	}

	if (ArgError) {
		RetVal = false;
		switch (ArgError) {
			case 1:
				m_ParseError = "*** Error: Not enough arguments for '" + argv[0] + "' command";
				break;
			case 2:
				m_ParseError = "*** Error: Too many arguments for '" + argv[0] + "' command";
				break;
			case 3:
				m_ParseError = "*** Error: Illegal argument for '" + argv[0] + "' command";
				break;
		}
	}

	return RetVal;
}


bool CDisassembler::ReadSourceFile(const std::string & szFilename, unsigned int nLoadAddress, const std::string & szDFCLibrary, std::ostream *msgFile, std::ostream *errFile)
{
	if (szDFCLibrary.empty()) return false;
	if (szFilename.empty()) return false;

	std::fstream theFile;
	const CDFCObject *theDFC = CDFCArray::instance()->locateDFC(szDFCLibrary);
	bool RetVal = true;

	if (msgFile) {
		(*msgFile) << "Loading \"" << szFilename << "\" at offset "
					<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << nLoadAddress
					<< std::nouppercase << std::setbase(0) << " using " << szDFCLibrary << " library...\n";
	}
	if (theDFC == NULL) {
		if (errFile) {
			(*errFile) << "*** Error: Can't open DFC Library \"" << szDFCLibrary << "\" to read \"" << szFilename << "\"\n";
		}
		RetVal = false;
	} else {
		theFile.open(szFilename.c_str(), std::ios_base::in | std::ios_base::binary);
		if (theFile.is_open() == 0) {
			if (errFile) {
				(*errFile) << "*** Error: Can't open file \"" << szFilename << "\" for reading\n";
			}
			RetVal = false;
		} else {
			int Status = 1;
			m_nFilesLoaded++;
			m_sInputFileList.push_back(szFilename);
			try {
				Status = theDFC->ReadDataFile(&theFile, nLoadAddress, m_Memory, DMEM_LOADED);
			}
			catch (const EXCEPTION_ERROR* aErr) {
				RetVal = false;
				m_nFilesLoaded--;
				m_sInputFileList.erase(m_sInputFileList.end()-1);
				switch (aErr->cause) {
					case EXCEPTION_ERROR::ERR_CHECKSUM:
						if (errFile) {
							(*errFile) << "*** Error: Checksum error reading file \"" << szFilename << "\"\n";
						}
						break;
					case EXCEPTION_ERROR::ERR_UNEXPECTED_EOF:
						if (errFile) {
							(*errFile) << "*** Error: Unexpected end-of-file reading \"" << szFilename << "\"\n";
						}
						break;
					case EXCEPTION_ERROR::ERR_OVERFLOW:
						if (errFile) {
							(*errFile) << "*** Error: Reading file \"" << szFilename << "\" extends past the defined memory limits of this processor\n";
						}
						break;
					case EXCEPTION_ERROR::ERR_READFAILED:
						if (errFile) {
							(*errFile) << "*** Error: Reading file \"" << szFilename << "\"\n";
						}
						break;
					default:
						if (errFile) {
							(*errFile) << "*** Error: Unknown DFC Error encountered while reading file \"" << szFilename << "\"\n";
						}
				}
			}
			if (Status == 0) {
				RetVal = false;
				if (errFile) {
					(*errFile) << "*** Warning: Reading file \"" << szFilename << "\", overlaps previously loaded files\n";
				}
			}
			theFile.close();
		}
	}
	// Note, the DFC will unload when destructor is called upon exiting this routine
	return RetVal;
}


bool CDisassembler::ValidateLabelName(const std::string & aName)
{
	if (aName.empty()) return false;					// Must have a length
	if ((!isalpha(aName.at(0))) && (aName.at(0) != '_')) return false;	// Must start with alpha or '_'
	for (unsigned int i=1; i<aName.size(); ++i) {
		if ((!isalnum(aName.at(i))) && (aName.at(i) != '_')) return false;	// Each character must be alphanumeric or '_'
	}
	return true;
}

// bool CDisassembler::ResolveIndirect(unsigned int nAddress, unsigned int& nResAddress, int nType) = 0;		// Purely Virtual!
//		NOTE: This function should set the m_Memory type code for the affected bytes to
//				either DMEM_CODEINDIRECT or DMEM_DATAINDIRECT!!!!   It should set
//				nResAddress to the resolved address and return T/F -- True if indirect
//				vector word lies completely inside the loaded space.  False if indirect
//				vector word (or part of it) is outside.  This function is NOT to check
//				the destination for loaded status -- that is checked by the routine
//				calling this function...  nType will be 0 for Code and 1 for Data...
//				Typically nType can be added to DMEM_CODEINDIRECT to determine the correct
//				code to store.  This is because the DMEM enumeration was created with
//				this expansion and uniformity in mind.
//				It is also good for this function to check that all bytes of the indirect
//				vector itself have previously not been "looked at" or tagged.  Routines
//				calling this function for previously tagged addresses should reset the
//				vector bytes to DMEM_LOADED.


bool CDisassembler::IsAddressLoaded(unsigned int nAddress, int nSize)
{
	bool RetVal = true;

	for (int i=0; ((i<nSize) && (RetVal)); ++i) {
		RetVal = RetVal && (m_Memory->GetDescriptor(nAddress + i) != DMEM_NOTLOADED);
	}
	return RetVal;
}


bool CDisassembler::AddLabel(unsigned int nAddress, bool bAddRef, unsigned int nRefAddress, const std::string & szLabel)
{
	TLabelTableMap::iterator itrLabelTable = m_LabelTable.find(nAddress);
	TAddressTableMap::iterator itrRefTable = m_LabelRefTable.find(nAddress);
	if (itrLabelTable != m_LabelTable.end()) {
		if (itrRefTable == m_LabelRefTable.end()) {
			assert(false);			// We should have an array for both label strings and addresses -- check adding!
			return false;
		}
		if (bAddRef) {				// Search and add reference, even if we find the string
			bool bFound = false;
			for (unsigned int i=0; i<itrRefTable->second.size(); ++i) {
				if (itrRefTable->second.at(i) == nRefAddress) {
					bFound = true;
					break;
				}
			}
			if (!bFound) itrRefTable->second.push_back(nRefAddress);
		}
		for (unsigned int i=0; i<itrLabelTable->second.size(); ++i) {
			if (compareNoCase(szLabel, itrLabelTable->second.at(i)) == 0) return false;
		}
	} else {
		assert(itrRefTable == m_LabelRefTable.end());		// If we don't have an entry in the label tabel, we shouldn't have any reference label table
		m_LabelTable[nAddress] = TStringArray();
		itrLabelTable = m_LabelTable.find(nAddress);
		m_LabelRefTable[nAddress] = TDWordArray();
		itrRefTable = m_LabelRefTable.find(nAddress);
		if (bAddRef) {				// If we are just now adding the label, we can add the ref without searching because it doesn't exist either
			itrRefTable->second.push_back(nRefAddress);
		}
	}
	if (itrLabelTable->second.size()) {
		if (!szLabel.empty()) {
			for (TStringArray::iterator itrLabels = itrLabelTable->second.begin(); itrLabels != itrLabelTable->second.end(); ++itrLabels) {
				if (itrLabels->empty()) {
					itrLabelTable->second.erase(itrLabels);
					break;							// If adding a non-Lxxxx entry, remove previous Lxxxx entry if it exists!
				}
			}
		} else {
			return false;		// Don't set Lxxxx entry if we already have at least 1 label!
		}
	}
	itrLabelTable->second.push_back(szLabel);
	return true;
}

bool CDisassembler::AddBranch(unsigned int nAddress, bool bAddRef, unsigned int nRefAddress)
{
	TAddressTableMap::iterator itrRefList = m_BranchTable.find(nAddress);
	if (itrRefList == m_BranchTable.end()) {
		m_BranchTable[nAddress] = TDWordArray();
		itrRefList = m_BranchTable.find(nAddress);
	}
	if (bAddRef) {				// Search and add reference
		bool bFound = false;
		for (unsigned int i = 0; i < itrRefList->second.size(); ++i) {
			if (itrRefList->second.at(i) == nRefAddress) {
				bFound = true;
				break;
			}
		}
		if (!bFound) itrRefList->second.push_back(nRefAddress);
	}
	return IsAddressLoaded(nAddress, 1);
}

void CDisassembler::GenDataLabel(unsigned int nAddress, unsigned int nRefAddress, const std::string & /* szLabel */, std::ostream *msgFile, std::ostream * /* errFile */)
{
	if (AddLabel(nAddress, true, nRefAddress)) OutputGenLabel(nAddress, msgFile);
}

void CDisassembler::GenAddrLabel(unsigned int nAddress, unsigned int nRefAddress, const std::string & /* szLabel */, std::ostream *msgFile, std::ostream *errFile)
{
	if (AddLabel(nAddress, false, nRefAddress)) OutputGenLabel(nAddress, msgFile);
	if (AddBranch(nAddress, true, nRefAddress) == false) {
		if (errFile) {
			if ((errFile == msgFile) || (LAdrDplyCnt != 0)) {
				(*errFile) << "\n";
				LAdrDplyCnt = 0;
			}
			(*errFile) << "     *** Warning:  Branch Ref: "
						<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << nAddress
						<< std::nouppercase << std::setbase(0) << " is outside of Loaded Source File.\n";
		}
	}
}

void CDisassembler::OutputGenLabel(unsigned int nAddress, std::ostream *msgFile)
{
	std::string Temp;

	if (msgFile == NULL) return;
	Temp = GenLabel(nAddress);
	Temp += ' ';
	if (Temp.size() < 7) {
		Temp += "       ";
		Temp = Temp.substr(0, 7);
	}
	if (LAdrDplyCnt >= 9) {
		std::size_t nPos = Temp.find(' ');
		if (nPos != std::string::npos) Temp = Temp.substr(0, nPos);
		Temp += '\n';
		LAdrDplyCnt=0;
	} else {
		LAdrDplyCnt++;
	}

	(*msgFile) << Temp;
}

std::string CDisassembler::GenLabel(unsigned int nAddress)
{
	std::ostringstream sstrTemp;

	sstrTemp << "L" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << nAddress;
	return sstrTemp.str();
}

bool CDisassembler::ScanEntries(std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;
	unsigned int nCount = m_EntryTable.size();

	if (m_bSpitFlag) {
		m_PC = 0;		// In spit mode, we start at first address and just spit
		return FindCode(msgFile, errFile);
	}

	TAddressMap::const_iterator itrEntry = m_EntryTable.begin();
	while (RetVal && (itrEntry != m_EntryTable.end())) {
		m_PC = itrEntry->first;
		++itrEntry;

		RetVal = RetVal && FindCode(msgFile, errFile);

		if (nCount != m_EntryTable.size()) {
			nCount = m_EntryTable.size();
			itrEntry = m_EntryTable.begin();			// If one gets added during the find process, our iterator gets invalidated and we must start over...
		}
	}
	return RetVal;
}

bool CDisassembler::ScanBranches(std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;
	unsigned int nCount = m_BranchTable.size();

	if (m_bSpitFlag) return true;						// Don't do anything in spit mode cause we did it in ScanEntries!

	TAddressTableMap::const_iterator itrEntry = m_BranchTable.begin();
	while (RetVal && (itrEntry != m_BranchTable.end())) {
		m_PC = itrEntry->first;
		++itrEntry;

		RetVal = RetVal && FindCode(msgFile, errFile);

		if (nCount != m_BranchTable.size()) {
			nCount = m_BranchTable.size();
			itrEntry = m_BranchTable.begin();			// If one gets added during the find process, our iterator gets invalidated and we must start over...
		}
	}
	return RetVal;
}

bool CDisassembler::ScanData(const std::string & szExcludeChars, std::ostream * /* msgFile */, std::ostream * /* errFile */)
{
	unsigned char c;

	// Note that we use an argument passed in so that the caller has a chance to change the
	//	list passed in by the GetExcludedPrintChars function!

	for (m_PC=0; m_PC<m_Memory->GetMemSize(); m_PC++) {
		if (m_Memory->GetDescriptor(m_PC) != DMEM_LOADED) continue;	// Only modify memory locations that have been loaded but not processed!
		c = m_Memory->GetByte(m_PC);
		if (isprint(c) && (szExcludeChars.find(c) == std::string::npos)) {
			m_Memory->SetDescriptor(m_PC, DMEM_PRINTDATA);
		} else {
			m_Memory->SetDescriptor(m_PC, DMEM_DATA);
		}
	}
	return true;
}

bool CDisassembler::FindCode(std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;
	bool TFlag = false;

	while (TFlag == false) {
		if (m_PC >= m_Memory->GetMemSize()) {
			TFlag = true;
			continue;
		}
		if ((m_Memory->GetDescriptor(m_PC) != DMEM_LOADED) && (m_bSpitFlag == false)) {
			TFlag = true;
			continue;					// Exit when we hit an area we've already looked at
		}
		if (ReadNextObj(true, msgFile, errFile)) {		// Read next opcode and tag memory since we are finding code here
			if (((m_CurrentOpcode.m_Control & OCTL_STOP) != 0) && (m_bSpitFlag == false)) TFlag = true;
		}	// If the ReadNextObj returns false, that means we hit an illegal opcode byte.  The ReadNextObj will have incremented the m_PC past that byte, so we'll keep processing
	}

	return RetVal;
}

bool CDisassembler::ReadNextObj(bool bTagMemory, std::ostream *msgFile, std::ostream *errFile)
{
	// Here, we'll read the next object code from memory and flag the memory as being
	//	code, unless an illegal opcode is encountered whereby it will be flagged as
	//	illegal code.  m_OpMemory is cleared and loaded with the memory bytes for the
	//	opcode that was processed.  m_CurrentOpcode will be also be set to the opcode
	//	that corresponds to the one found.  m_PC will also be incremented by the number
	//	of bytes in the complete opcode and in the case of an illegal opcode, it will
	//	increment only by 1 byte so we can then test the following byte to see if it
	//	is legal to allow us to get back on track.  This function will return True
	//	if the opcode was correct and properly formed and fully existed in memory.  It
	//	will return false if the opcode was illegal or if the opcode crossed over the
	//	bounds of loaded source memory.
	// If bTagMemory is false, then memory descriptors aren't changed!  This is useful
	//	if on-the-fly disassembly is desired without modifying the descriptors, such
	//	as in pass 2 of the disassembly process.

	unsigned char FirstByte;
	unsigned int SavedPC;
	bool Flag;

	m_sFunctionalOpcode = "";

	FirstByte = m_Memory->GetByte(m_PC++);
	m_OpMemory.clear();
	m_OpMemory.push_back(FirstByte);
	if (IsAddressLoaded(m_PC-1, 1) == false) return false;

	COpcodeTable::const_iterator itrOpcode = m_Opcodes.find(FirstByte);
	Flag = false;
	if (itrOpcode != m_Opcodes.end()) {
		for (unsigned int ndx = 0; ((ndx < itrOpcode->second.size()) && (Flag == false)); ++ndx) {
			m_CurrentOpcode = itrOpcode->second.at(ndx);
			Flag = true;
			for (unsigned int i=1; ((i<m_CurrentOpcode.m_OpcodeBytes.size()) && (Flag)); ++i) {
				if (m_CurrentOpcode.m_OpcodeBytes.at(i) != m_Memory->GetByte(m_PC+i-1)) Flag = false;
			}
		}
	}
	if ((Flag == false) || (IsAddressLoaded(m_PC, m_CurrentOpcode.m_OpcodeBytes.size()-1) == false)) {
		if (bTagMemory) m_Memory->SetDescriptor(m_PC-1, DMEM_ILLEGALCODE);
		return false;
	}

	// If we get here, then we've found a valid matching opcode.  m_CurrentOpcode has been set to the opcode value
	//	so we must now finish copying to m_OpMemory, tag the bytes in memory, increment m_PC, and call CompleteObjRead
	//	to handle the processor dependent stuff.  If CompleteObjRead returns FALSE, then we'll have to undo everything
	//	and return flagging an invalid opcode.
	SavedPC = m_PC;		// Remember m_PC in case we have to undo things (remember, m_PC has already been incremented by 1)
	for (unsigned int i=1; i<m_CurrentOpcode.m_OpcodeBytes.size(); ++i) {			// Finish copying opcode, but don't tag memory until dependent code is called successfully
		m_OpMemory.push_back(m_Memory->GetByte(m_PC++));
	}

	if ((CompleteObjRead(true, msgFile, errFile) == false) || (IsAddressLoaded(SavedPC-1, m_OpMemory.size()) == false))  {
		// Undo things here:
		m_OpMemory.clear();
		m_OpMemory.push_back(FirstByte);		// Keep only the first byte in OpMemory for illegal opcode id
		m_PC = SavedPC;
		if (bTagMemory) m_Memory->SetDescriptor(m_PC-1, DMEM_ILLEGALCODE);
		return false;
	}


//	assert(CompleteObjRead(true, msgFile, errFile));


	SavedPC--;
	for (unsigned int i=0; i<m_OpMemory.size(); ++i) {		// CompleteObjRead will add bytes to OpMemory, so we simply have to flag memory for that many bytes.  m_PC is already incremented by CompleteObjRead
		if (bTagMemory) m_Memory->SetDescriptor(SavedPC, DMEM_CODE);
		SavedPC++;
	}
	assert(SavedPC == m_PC);		// If these aren't equal, something is wrong in the CompleteObjRead!  m_PC should be incremented for every byte added to m_OpMemory by the complete routine!
	return true;
}

bool CDisassembler::Disassemble(std::ostream *msgFile, std::ostream *errFile, std::ostream *outFile)
{
	bool RetVal = true;
	std::ostream *theOutput;
	std::fstream aOutput;
	std::string Temp;

	if (outFile) {
		theOutput = outFile;
	} else {
		aOutput.open(m_sOutputFilename.c_str(), std::ios_base::out | std::ios_base::trunc);
		if (!aOutput.is_open()) {
			if (errFile) {
				(*errFile) << "\n*** Error: Opening file \"" << m_sOutputFilename << "\" for writing...\n";
			}
			return false;
		}
		theOutput = &aOutput;
	}

	while (1) {		// Setup dummy endless loop so we can use the break
		if (msgFile) (*msgFile) << "\nPass 1 - Finding Code, Data, and Labels...\n";
		RetVal = Pass1(*theOutput, msgFile, errFile);
		if (!RetVal) break;

		if (msgFile) {
			(*msgFile) << ((LAdrDplyCnt != 0) ? '\n' : ' ') << "\nPass 2 - Disassembling to Output File...\n";
		}
		RetVal = Pass2(*theOutput, msgFile, errFile);
		if (!RetVal) break;

		if (!m_sFunctionsFilename.empty()) {
			if (*msgFile) {
				(*msgFile) << ((LAdrDplyCnt != 0) ? '\n' : ' ') << "\nPass 3 - Creating Functions Output File...\n";
			}

			RetVal = Pass3(*theOutput, msgFile, errFile);
			if (!RetVal) break;
		}

		if (msgFile) {
			(*msgFile) << "\nDisassembly Complete\n";
		}

		// Add additional Passes here and end this loop with a break
		break;
	}

	if (RetVal == false) {
		(*theOutput) << "\n*** Internal error encountered while disassembling.\n";
		if (errFile) (*errFile) << "\n*** Internal error encountered while disassembling.\n";
	}

	if (aOutput.is_open()) aOutput.close();		// Close the output file if we opened it

	return RetVal;
}

bool CDisassembler::Pass1(std::ostream& /* outFile */, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;

	// Note that Short-Circuiting will keep following process stages from being called in the even of an error!
	RetVal = RetVal && ScanEntries(msgFile, errFile);
	RetVal = RetVal && ScanBranches(msgFile, errFile);
	RetVal = RetVal && ScanData(GetExcludedPrintChars(), msgFile, errFile);

	return RetVal;
}

bool CDisassembler::Pass2(std::ostream& outFile, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;

	// Note that Short-Circuiting will keep following process stages from being called in the even of an error!
	RetVal = RetVal && WriteHeader(outFile, msgFile, errFile);
	RetVal = RetVal && WriteEquates(outFile, msgFile, errFile);
	RetVal = RetVal && WriteDisassembly(outFile, msgFile, errFile);

	return RetVal;
}

bool CDisassembler::Pass3(std::ostream& /* outFile */, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal = true;
	std::fstream aFunctionsFile;
	bool bInFunc;
	bool bLastFlag;
	bool bBranchOutFlag;
	unsigned int nFuncAddr = 0;
	unsigned int nSavedPC;
	TMemRange *pMemRange;
	bool bTempFlag;
	bool bTempFlag2;

	aFunctionsFile.open(m_sFunctionsFilename.c_str(), std::ios_base::out | std::ios_base::trunc);
	if (!aFunctionsFile.is_open()) {
		if (errFile) {
			(*errFile) << "\n*** Error: Opening file \"" << m_sFunctionsFilename << "\" for writing...\n";
		}
		return false;
	}

	aFunctionsFile << ";\n";
	aFunctionsFile << "; " << GetGDCLongName() << " Generated Function Information File\n";
	aFunctionsFile << ";\n";
	aFunctionsFile << ";    Control File" << ((m_sControlFileList.size() > 1) ? "s:" : ": ") << " ";
	for (unsigned int i=0; i<m_sControlFileList.size(); ++i) {
		if (i==0) {
			aFunctionsFile << m_sControlFileList.at(i) << "\n";
		} else {
			aFunctionsFile << ";                  " << m_sControlFileList.at(i) << "\n";
		}
	}
	aFunctionsFile << ";      Input File" << ((m_sInputFileList.size() > 1) ? "s:" : ": ") << " ";
	for (unsigned int i=0; i<m_sInputFileList.size(); ++i) {
		if (i==0) {
			aFunctionsFile << m_sInputFileList.at(i) << "\n";
		} else {
			aFunctionsFile << ";                  " << m_sInputFileList.at(i) << "\n";
		}
	}
	aFunctionsFile << ";     Output File:  " << m_sOutputFilename << "\n";
	aFunctionsFile << ";  Functions File:  " << m_sFunctionsFilename << "\n";
	aFunctionsFile << ";\n";

	aFunctionsFile << "; Memory Mappings:";

	aFunctionsFile << "  ROM Memory Map: ";
	if (m_ROMMemMap.IsNullRange()) {
		aFunctionsFile << "<Not Defined>\n";
	} else {
		aFunctionsFile << "\n";

		pMemRange = &m_ROMMemMap;
		while (pMemRange) {
			aFunctionsFile << ";                       "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
							<< std::nouppercase << std::setbase(0) << " - "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
							<< std::nouppercase << std::setbase(0) << "  (Size: "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
							<< std::nouppercase << std::setbase(0) << ")\n";
			pMemRange = pMemRange->GetNext();
		}
	}

	aFunctionsFile << ";                   RAM Memory Map: ";
	if (m_RAMMemMap.IsNullRange()) {
		aFunctionsFile << "<Not Defined>\n";
	} else {
		aFunctionsFile << "\n";

		pMemRange = &m_RAMMemMap;
		while (pMemRange) {
			aFunctionsFile << ";                       "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
							<< std::nouppercase << std::setbase(0) << " - "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
							<< std::nouppercase << std::setbase(0) << "  (Size: "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
							<< std::nouppercase << std::setbase(0) << ")\n";
			pMemRange = pMemRange->GetNext();
		}
	}

	aFunctionsFile << ";                    IO Memory Map: ";
	if (m_IOMemMap.IsNullRange()) {
		aFunctionsFile << "<Not Defined>\n";
	} else {
		aFunctionsFile << "\n";

		pMemRange = &m_IOMemMap;
		while (pMemRange) {
			aFunctionsFile << ";                       "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
							<< std::nouppercase << std::setbase(0) << " - "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
							<< std::nouppercase << std::setbase(0) << "  (Size: "
							<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
							<< std::nouppercase << std::setbase(0) << ")\n";
			pMemRange = pMemRange->GetNext();
		}
	}

	aFunctionsFile << ";\n";
	aFunctionsFile << ";       Generated:  " << std::ctime(&m_StartTime);		// Note: std::ctime adds extra \n character, so no need to add our own
	aFunctionsFile << ";\n\n";

	bTempFlag = false;
	if (!m_ROMMemMap.IsNullRange()) {
		pMemRange = &m_ROMMemMap;
		while (pMemRange) {
			std::ostringstream sstrTemp;

			sstrTemp << "#ROM|" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr();
			sstrTemp << "|"  << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize();
			sstrTemp << "\n";
			m_sFunctionalOpcode = sstrTemp.str();

			aFunctionsFile << m_sFunctionalOpcode;
			pMemRange = pMemRange->GetNext();
		}
		bTempFlag = true;
	}
	if (!m_RAMMemMap.IsNullRange()) {
		pMemRange = &m_RAMMemMap;
		while (pMemRange) {
			std::ostringstream sstrTemp;

			sstrTemp << "#RAM|" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr();
			sstrTemp << "|"  << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize();
			sstrTemp << "\n";
			m_sFunctionalOpcode = sstrTemp.str();

			aFunctionsFile << m_sFunctionalOpcode;
			pMemRange = pMemRange->GetNext();
		}
		bTempFlag = true;
	}
	if (!m_IOMemMap.IsNullRange()) {
		pMemRange = &m_IOMemMap;
		while (pMemRange) {
			std::ostringstream sstrTemp;

			sstrTemp << "#IO|" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr();
			sstrTemp << "|"  << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize();
			sstrTemp << "\n";
			m_sFunctionalOpcode = sstrTemp.str();

			aFunctionsFile << m_sFunctionalOpcode;
			pMemRange = pMemRange->GetNext();
		}
		bTempFlag = true;
	}
	if (bTempFlag) aFunctionsFile << "\n";

	bTempFlag = false;
	for (m_PC = 0; ((m_PC < m_Memory->GetMemSize()) && (RetVal)); m_PC++) {
		TLabelTableMap::const_iterator itrLabels = m_LabelTable.find(m_PC);
		if (itrLabels != m_LabelTable.end()) {
			std::ostringstream sstrTemp;
			bTempFlag2 = false;
			sstrTemp << "!" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << m_PC;
			sstrTemp << std::nouppercase << std::setbase(0) << "|";
			for (unsigned int i = 0; i < itrLabels->second.size(); ++i) {
				if (bTempFlag2) sstrTemp << ",";
				if (!itrLabels->second.at(i).empty()) {
					sstrTemp << itrLabels->second.at(i);
					bTempFlag2 = true;
				}
			}
			sstrTemp << "\n";
			m_sFunctionalOpcode = sstrTemp.str();
			if (bTempFlag2) aFunctionsFile << m_sFunctionalOpcode;
			bTempFlag = true;
		}
	}
	if (bTempFlag) aFunctionsFile << "\n";

	bInFunc = false;
	for (m_PC = 0; ((m_PC < m_Memory->GetMemSize()) && (RetVal)); ) {
		bLastFlag = false;
		bBranchOutFlag = false;

		// Check for function start/end flags:
		TAddressMap::const_iterator itrFunction = m_FunctionsTable.find(m_PC);
		if (itrFunction != m_FunctionsTable.end()) {
			switch (itrFunction->second) {
				case FUNCF_HARDSTOP:
				case FUNCF_EXITBRANCH:
				case FUNCF_SOFTSTOP:
					bInFunc = false;
					bLastFlag = true;
					break;

				case FUNCF_BRANCHOUT:
					bBranchOutFlag = true;
					break;

				case FUNCF_BRANCHIN:
					if (bInFunc) break;		// Continue if already inside a function
					// Else, fall-through and setup for new function:
				case FUNCF_ENTRY:
				case FUNCF_INDIRECT:
				case FUNCF_CALL:
				{
					std::ostringstream sstrTemp;
					sstrTemp << "@" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << m_PC << "|";
					m_sFunctionalOpcode = sstrTemp.str();

					TLabelTableMap::const_iterator itrLabels = m_LabelTable.find(m_PC);
					if (itrLabels != m_LabelTable.end()) {
						for (unsigned int i = 0; i < itrLabels->second.size(); ++i) {
							if (i != 0) m_sFunctionalOpcode += ",";
							m_sFunctionalOpcode += FormatLabel(LC_REF, itrLabels->second.at(i), m_PC);
						}
					} else {
						m_sFunctionalOpcode += "???";
					}

					aFunctionsFile << m_sFunctionalOpcode;
					aFunctionsFile << "\n";

					nFuncAddr = m_PC;
					bInFunc = true;
					break;
				}

				default:
					assert(false);			// Unexpected Function Flag!!  Check Code!!
					RetVal = false;
					continue;
			}
		}

		nSavedPC = m_PC;
		m_sFunctionalOpcode = "";
		switch (m_Memory->GetDescriptor(m_PC)) {
			case DMEM_NOTLOADED:
				m_PC++;
				bLastFlag = bInFunc;
				bInFunc = false;
				break;
			case DMEM_LOADED:
				assert(false);		// WARNING!  All loaded code should have been evaluated.  Check override code!
				RetVal = false;
				m_PC++;
				break;
			case DMEM_DATA:
			case DMEM_PRINTDATA:
			case DMEM_CODEINDIRECT:
			case DMEM_DATAINDIRECT:
			case DMEM_ILLEGALCODE:
			{
				std::ostringstream sstrTemp;
				sstrTemp << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << m_PC << "|";
				m_sFunctionalOpcode = sstrTemp.str();

				TLabelTableMap::const_iterator itrLabels = m_LabelTable.find(m_PC);
				if (itrLabels != m_LabelTable.end()) {
					for (unsigned int i=0; i<itrLabels->second.size(); ++i) {
						if (i != 0) m_sFunctionalOpcode += ",";
						m_sFunctionalOpcode += FormatLabel(LC_REF, itrLabels->second.at(i), m_PC);
					}
				}

				sstrTemp.str(std::string());
				sstrTemp << std::uppercase << std::setfill('0') << std::setw(2) << std::setbase(16) << m_Memory->GetByte(m_PC) << "|";
				m_sFunctionalOpcode += sstrTemp.str();

				m_PC++;
				break;
			}
			case DMEM_CODE:
				RetVal = ReadNextObj(false, msgFile, errFile);
				break;
			default:
				bInFunc = false;
				RetVal = false;
				break;
		}

		if (!m_sFunctionalOpcode.empty()) {
			std::ostringstream sstrTemp;
			sstrTemp << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (nSavedPC - nFuncAddr) << "|";
			m_sFunctionalOpcode = sstrTemp.str() + m_sFunctionalOpcode;
		}

		if (bBranchOutFlag) {
			TAddressMap::const_iterator itrFunction = m_FunctionsTable.find(m_PC);
			if (itrFunction != m_FunctionsTable.end()) {
				switch (itrFunction->second) {
					case FUNCF_ENTRY:
					case FUNCF_INDIRECT:
					case FUNCF_CALL:
						bInFunc = false;
						bLastFlag = true;
						break;
				}
			} else {
				bInFunc = false;
				bLastFlag = true;
			}
		}

		if (bLastFlag) {
			TAddressMap::const_iterator itrFunction = m_FunctionsTable.find(m_PC);
			if (itrFunction != m_FunctionsTable.end()) {
				switch (itrFunction->second) {
					case FUNCF_BRANCHIN:
						bLastFlag = false;
						bInFunc = true;
						break;
				}
			}
		}

		if ((bInFunc) || (bLastFlag)) {
			if (!m_sFunctionalOpcode.empty()) {
				aFunctionsFile << m_sFunctionalOpcode;
				aFunctionsFile << "\n";
			}
			if (bLastFlag) aFunctionsFile << "\n";
		}
	}

	aFunctionsFile.close();

	return RetVal;
}

std::string CDisassembler::FormatComments(MNEMONIC_CODE /* nMCCode */)		// The default returns the reference comment string.
{
	return FormatReferences(m_PC - m_OpMemory.size());
}

std::string CDisassembler::FormatAddress(unsigned int nAddress)
{
	std::ostringstream sstrTemp;

	sstrTemp << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << nAddress;
	return sstrTemp.str();
}

std::string CDisassembler::FormatOpBytes()
{
	std::ostringstream sstrTemp;

	for (unsigned int i=0; i<m_OpMemory.size(); ++i) {
		sstrTemp << std::uppercase << std::setfill('0') << std::setw(2) << std::setbase(16) << static_cast<unsigned int>(m_OpMemory.at(i))
					<< std::nouppercase << std::setbase(0);
		if (i < m_OpMemory.size()-1) sstrTemp << " ";
	}
	return sstrTemp.str();
}

std::string CDisassembler::FormatLabel(LABEL_CODE /* nLC */, const std::string & szLabel, unsigned int nAddress)
{
	std::ostringstream sstrTemp;

	if (szLabel.empty()) {
		sstrTemp << "L" << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << nAddress;
	} else {
		sstrTemp << szLabel;
	}

	return sstrTemp.str();
}

std::string CDisassembler::FormatReferences(unsigned int nAddress)
{
	std::string RetVal;
	bool Flag;

	RetVal = "";
	Flag = false;
	TAddressTableMap::const_iterator itrBranches = m_BranchTable.find(nAddress);
	if (itrBranches != m_BranchTable.end()) {
		if (itrBranches->second.size() != 0) {
			RetVal += "CRef: ";
			Flag = true;
			for (unsigned int i=0; i<itrBranches->second.size(); ++i) {
				std::ostringstream sstrTemp;
				sstrTemp << GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << itrBranches->second.at(i);
				RetVal += sstrTemp.str();
				if (i < itrBranches->second.size()-1) RetVal += ",";
			}
		}
	}

	if (m_LabelTable.find(nAddress) != m_LabelTable.end()) {
		TAddressTableMap::const_iterator itrLabelRef = m_LabelRefTable.find(nAddress);
		if (itrLabelRef == m_LabelRefTable.end()) {
			assert(false);		// Should also have a ref entry!
			return RetVal;
		}

		if (itrLabelRef->second.size() != 0) {
			if (Flag) RetVal += "; ";
			RetVal += "DRef: ";
			Flag = true;
			for (unsigned int i=0; i<itrLabelRef->second.size(); ++i) {
				std::ostringstream sstrTemp;
				sstrTemp << GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << itrLabelRef->second.at(i);
				RetVal += sstrTemp.str();

				if (i < itrLabelRef->second.size()-1) RetVal += ",";
			}
		}
	}

	return RetVal;
}


bool CDisassembler::WriteHeader(std::ostream& outFile, std::ostream * /* msgFile */, std::ostream * /* errFile */)
{
	TStringArray OutLine;
	TMemRange *pMemRange;

	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(0);

	OutLine[FC_LABEL] = GetCommentStartDelim() + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	OutLine[FC_LABEL] = GetCommentStartDelim() + " " + GetGDCLongName() + " Generated Source Code " + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	OutLine[FC_LABEL] = GetCommentStartDelim() + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	OutLine[FC_LABEL] = GetCommentStartDelim() + "    Control File";
	OutLine[FC_LABEL] += ((m_sControlFileList.size() > 1) ? "s: " : ":  ");
	for (unsigned int i=0; i<m_sControlFileList.size(); ++i) {
		if (i==0) {
			OutLine[FC_LABEL] += m_sControlFileList.at(i) + "  " + GetCommentEndDelim() + "\n";
		} else {
			OutLine[FC_LABEL] = GetCommentStartDelim() + "                  " + m_sControlFileList.at(i) + "  " + GetCommentEndDelim() + "\n";
		}
		outFile << MakeOutputLine(OutLine) << "\n";
	}
	OutLine[FC_LABEL] = GetCommentStartDelim() + "      Input File";
	OutLine[FC_LABEL] += ((m_sInputFileList.size() > 1) ? "s: " : ":  ");
	for (unsigned int i=0; i<m_sInputFileList.size(); ++i) {
		if (i==0) {
			OutLine[FC_LABEL] += m_sInputFileList.at(i) +  "  " + GetCommentEndDelim() + "\n";
		} else {
			OutLine[FC_LABEL] = GetCommentStartDelim() + "                  " + m_sInputFileList.at(i) + "  " + GetCommentEndDelim() + "\n";
		}
		outFile << MakeOutputLine(OutLine) << "\n";
	}
	OutLine[FC_LABEL] = GetCommentStartDelim() + "     Output File:  " + m_sOutputFilename + "  " + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	if (!m_sFunctionsFilename.empty()) {
		OutLine[FC_LABEL] = GetCommentStartDelim() + "  Functions File:  " + m_sFunctionsFilename + "  " + GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";
	}
	OutLine[FC_LABEL] = GetCommentStartDelim() + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";

	OutLine[FC_LABEL] = GetCommentStartDelim() + " Memory Mappings:";

	OutLine[FC_LABEL] += "  ROM Memory Map: ";
	if (m_ROMMemMap.IsNullRange()) {
		OutLine[FC_LABEL] += "<Not Defined>" + GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";
	} else {
		OutLine[FC_LABEL] += GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";

		pMemRange = &m_ROMMemMap;
		while (pMemRange) {
			std::ostringstream sstrTemp;
			sstrTemp << GetCommentStartDelim() << "                       "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
			<< std::nouppercase << std::setbase(0) << " - "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
			<< std::nouppercase << std::setbase(0) << "  (Size: "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
			<< std::nouppercase << std::setbase(0) << ")  " << GetCommentEndDelim() << "\n";
			OutLine[FC_LABEL] = sstrTemp.str();
			outFile << MakeOutputLine(OutLine) << "\n";
			pMemRange = pMemRange->GetNext();
		}
	}

	OutLine[FC_LABEL] = GetCommentStartDelim() + "                   RAM Memory Map: ";
	if (m_RAMMemMap.IsNullRange()) {
		OutLine[FC_LABEL] += "<Not Defined>" + GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";
	} else {
		OutLine[FC_LABEL] += GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";

		pMemRange = &m_RAMMemMap;
		while (pMemRange) {
			std::ostringstream sstrTemp;
			sstrTemp << GetCommentStartDelim() << "                       "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
			<< std::nouppercase << std::setbase(0) << " - "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
			<< std::nouppercase << std::setbase(0) << "  (Size: "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
			<< std::nouppercase << std::setbase(0) << ")  " << GetCommentEndDelim() << "\n";
			OutLine[FC_LABEL] = sstrTemp.str();
			outFile << MakeOutputLine(OutLine) << "\n";
			pMemRange = pMemRange->GetNext();
		}
	}

	OutLine[FC_LABEL] = GetCommentStartDelim() + "                    IO Memory Map: ";
	if (m_IOMemMap.IsNullRange()) {
		OutLine[FC_LABEL] += "<Not Defined>" + GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";
	} else {
		OutLine[FC_LABEL] += GetCommentEndDelim() + "\n";
		outFile << MakeOutputLine(OutLine) << "\n";

		pMemRange = &m_IOMemMap;
		while (pMemRange) {
			std::ostringstream sstrTemp;
			sstrTemp << GetCommentStartDelim() << "                       "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetStartAddr()
			<< std::nouppercase << std::setbase(0) << " - "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << (pMemRange->GetStartAddr() + pMemRange->GetSize() - 1)
			<< std::nouppercase << std::setbase(0) << "  (Size: "
			<< GetHexDelim() << std::uppercase << std::setfill('0') << std::setw(4) << std::setbase(16) << pMemRange->GetSize()
			<< std::nouppercase << std::setbase(0) << ")  " << GetCommentEndDelim() << "\n";
			OutLine[FC_LABEL] = sstrTemp.str();
			outFile << MakeOutputLine(OutLine) << "\n";
			pMemRange = pMemRange->GetNext();
		}
	}

	OutLine[FC_LABEL] = GetCommentStartDelim() + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	OutLine[FC_LABEL] = GetCommentStartDelim() + "       Generated:  ";
	OutLine[FC_LABEL] += std::ctime(&m_StartTime);
	OutLine[FC_LABEL].erase(OutLine[FC_LABEL].end()-1);		// Note: std::ctime adds extra \n character
	OutLine[FC_LABEL] += GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	OutLine[FC_LABEL] = GetCommentStartDelim() + GetCommentEndDelim() + "\n";
	outFile << MakeOutputLine(OutLine) << "\n";


	OutLine[FC_LABEL].clear();
	outFile << MakeOutputLine(OutLine) << "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	return true;
}

bool CDisassembler::WritePreEquates(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default.
{
	return true;
}

bool CDisassembler::WriteEquates(std::ostream& outFile, std::ostream *msgFile, std::ostream *errFile)
{
	TStringArray OutLine;
	bool RetVal;

	m_OpMemory.clear();			// Remove bytes so all code will properly reference first and last PC addresses

	RetVal = false;
	if (WritePreEquates(outFile, msgFile, errFile)) {
		RetVal = true;
		ClearOutputLine(OutLine);
		for (m_PC = 0; m_PC < m_Memory->GetMemSize(); m_PC++) {
			assert(m_Memory->GetDescriptor(m_PC) != DMEM_LOADED);		// Find Routines didn't find and analyze all memory!!  Fix it!
			if (m_Memory->GetDescriptor(m_PC) != DMEM_NOTLOADED) continue;		// Loaded addresses will get outputted during main part

			TLabelTableMap::const_iterator itrLabels = m_LabelTable.find(m_PC);
			if (itrLabels != m_LabelTable.end()) {
				OutLine[FC_ADDRESS] = FormatAddress(m_PC);
				for (unsigned int i=0; i<itrLabels->second.size(); ++i) {
					OutLine[FC_LABEL] = FormatLabel(LC_EQUATE, itrLabels->second.at(i), m_PC);
					OutLine[FC_MNEMONIC] = FormatMnemonic(MC_EQUATE);
					OutLine[FC_OPERANDS] = FormatOperands(MC_EQUATE);
					OutLine[FC_COMMENT] = FormatComments(MC_EQUATE);
					outFile << MakeOutputLine(OutLine) << "\n";
				}
			}
		}
		RetVal = RetVal && WritePostEquates(outFile, msgFile, errFile);
	}
	return RetVal;
}

bool CDisassembler::WritePostEquates(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WritePreDisassembly(std::ostream& outFile, std::ostream * /* msgFile */, std::ostream * /* errFile */)
{
	TStringArray OutLine;

	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(0);

	outFile << MakeOutputLine(OutLine) << "\n";
	outFile << MakeOutputLine(OutLine) << "\n";
	return true;
}

bool CDisassembler::WriteDisassembly(std::ostream& outFile, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal;

	RetVal = false;
	if (WritePreDisassembly(outFile, msgFile, errFile)) {
		RetVal = true;

		for (m_PC = 0; ((m_PC < m_Memory->GetMemSize()) && (RetVal)); ) {	// WARNING!! WriteSection MUST increment m_PC
			switch (m_Memory->GetDescriptor(m_PC)) {
				case DMEM_NOTLOADED:
					m_PC++;
					break;
				case DMEM_LOADED:
					assert(false);		// WARNING!  All loaded code should have been evaluated.  Check override code!
					RetVal = false;
					m_PC++;
					break;
				case DMEM_DATA:
				case DMEM_PRINTDATA:
				case DMEM_CODEINDIRECT:
				case DMEM_DATAINDIRECT:
				case DMEM_CODE:
				case DMEM_ILLEGALCODE:
					RetVal = RetVal && WriteSection(outFile, msgFile, errFile);			// WARNING!! WriteSection MUST properly increment m_PC!!
					break;
			}
		}

		RetVal = RetVal && WritePostDisassembly(outFile, msgFile, errFile);
	}

	return RetVal;
}

bool CDisassembler::WritePostDisassembly(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WritePreSection(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WriteSection(std::ostream& outFile, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal;
	bool Done;

	RetVal = false;
	if (WritePreSection(outFile, msgFile, errFile)) {
		RetVal = true;

		Done = false;
		while ((m_PC < m_Memory->GetMemSize()) && (Done == false) && (RetVal)) {
			// WARNING!! Write Data and Code section functions MUST properly increment m_PC!!
			switch (m_Memory->GetDescriptor(m_PC)) {
				case DMEM_DATA:
				case DMEM_PRINTDATA:
				case DMEM_CODEINDIRECT:
				case DMEM_DATAINDIRECT:
					RetVal = RetVal && WriteDataSection(outFile, msgFile, errFile);
					break;
				case DMEM_CODE:
				case DMEM_ILLEGALCODE:
					RetVal = RetVal && WriteCodeSection(outFile, msgFile, errFile);
					break;
				default:
					Done = true;
					break;
			}
		}

		RetVal = RetVal && WritePostSection(outFile, msgFile, errFile);
	}

	return RetVal;
}

bool CDisassembler::WritePostSection(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WritePreDataSection(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WriteDataSection(std::ostream& outFile, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal;
	TStringArray OutLine;
	bool Done;
	unsigned int SavedPC;
	int Count;
	bool Flag;
	MEM_DESC Code;
	std::string TempLabel;
	TByteArray TempOpMemory;

	ClearOutputLine(OutLine);

	RetVal = false;
	if (WritePreDataSection(outFile, msgFile, errFile)) {
		RetVal = true;

		Done = false;
		while ((m_PC < m_Memory->GetMemSize()) && (Done == false) && (RetVal)) {
			ClearOutputLine(OutLine);
			OutLine[FC_ADDRESS] = FormatAddress(m_PC);
			TLabelTableMap::const_iterator itrLabels = m_LabelTable.find(m_PC);
			if (itrLabels != m_LabelTable.end()) {
				for (unsigned int i=1; i<itrLabels->second.size(); ++i) {
					OutLine[FC_LABEL] = FormatLabel(LC_DATA, itrLabels->second.at(i), m_PC);
					outFile << MakeOutputLine(OutLine) << "\n";
				}
				if (itrLabels->second.size()) OutLine[FC_LABEL] = FormatLabel(LC_DATA, itrLabels->second.at(0), m_PC);
			}

			SavedPC = m_PC;		// Keep a copy of the PC for this line because some calls will be incrementing our m_PC
			Code = (MEM_DESC)m_Memory->GetDescriptor(m_PC);
			if ((m_bAsciiFlag == false) && (Code == DMEM_PRINTDATA)) Code = DMEM_DATA;		// If not doing ASCII, treat print data as data
			switch (Code) {
				case DMEM_DATA:
					Count = 0;
					m_OpMemory.clear();
					Flag = false;
					while (Flag == false) {
						m_OpMemory.push_back(m_Memory->GetByte(m_PC++));
						Count++;
						// Stop on this line when we've either run out of data, hit the specified line limit, or hit another label
						if (Count >= m_nMaxNonPrint) Flag = true;
						if (m_LabelTable.find(m_PC) != m_LabelTable.end()) Flag = true;
						Code = (MEM_DESC)m_Memory->GetDescriptor(m_PC);
						if ((m_bAsciiFlag == false) && (Code == DMEM_PRINTDATA)) Code = DMEM_DATA;		// If not doing ASCII, treat print data as data
						if (Code != DMEM_DATA) Flag = true;
					}
					if (m_bDataOpBytesFlag) OutLine[FC_OPBYTES] = FormatOpBytes();
					OutLine[FC_MNEMONIC] = FormatMnemonic(MC_DATABYTE);
					OutLine[FC_OPERANDS] = FormatOperands(MC_DATABYTE);
					OutLine[FC_COMMENT] = FormatComments(MC_DATABYTE);
					outFile << MakeOutputLine(OutLine) << "\n";
					break;
				case DMEM_PRINTDATA:
					Count = 0;
					m_OpMemory.clear();
					Flag = false;
					while (Flag == false) {
						m_OpMemory.push_back(m_Memory->GetByte(m_PC++));
						Count++;
						// Stop on this line when we've either run out of data, hit the specified line limit, or hit another label
						if (Count >= m_nMaxPrint) Flag = true;
						if (m_LabelTable.find(m_PC) != m_LabelTable.end()) Flag = true;
						if (m_Memory->GetDescriptor(m_PC) != DMEM_PRINTDATA) Flag = true;
					}
					// First, print a line of the output bytes for reference:
					if (m_bAsciiBytesFlag) {
						TempLabel = OutLine[FC_LABEL];
						TempOpMemory = m_OpMemory;

						Count = TempOpMemory.size();
						while (Count) {
							m_OpMemory.clear();
							for (int i=0; ((i<Count) && (i<m_nMaxNonPrint)); ++i)
								m_OpMemory.push_back(TempOpMemory.at(TempOpMemory.size()-Count+i));
							OutLine[FC_LABEL] = GetCommentStartDelim() + " " + TempLabel +
												((!TempLabel.empty()) ? " " : "") +
												FormatOperands(MC_DATABYTE) + " " + GetCommentEndDelim();
							OutLine[FC_ADDRESS] = FormatAddress(m_PC-Count);
							OutLine[FC_MNEMONIC] = "";
							OutLine[FC_OPERANDS] = "";
							OutLine[FC_COMMENT] = "";
							outFile << MakeOutputLine(OutLine) << "\n";
							Count -= m_OpMemory.size();
						}

						OutLine[FC_LABEL] = TempLabel;
						m_OpMemory = TempOpMemory;
					}

					// Then, print the line as it should be in the ASCII equivalent:
					OutLine[FC_ADDRESS] = FormatAddress(SavedPC);
					if (m_bDataOpBytesFlag) OutLine[FC_OPBYTES] = FormatOpBytes();
					OutLine[FC_MNEMONIC] = FormatMnemonic(MC_ASCII);
					OutLine[FC_OPERANDS] = FormatOperands(MC_ASCII);
					OutLine[FC_COMMENT] = FormatComments(MC_ASCII);
					outFile << MakeOutputLine(OutLine) << "\n";
					break;
				case DMEM_CODEINDIRECT:
				case DMEM_DATAINDIRECT:
					// If the following call returns false, that means that the user (or
					//	special indirect detection logic) erroneously specified (or detected)
					//	the indirect.  So instead of throwing an error or causing problems,
					//	we will treat it as a data byte instead:
					if (RetrieveIndirect(msgFile, errFile) == false) {		// Bumps PC
						if (m_bDataOpBytesFlag) OutLine[FC_OPBYTES] = FormatOpBytes();
						OutLine[FC_MNEMONIC] = FormatMnemonic(MC_DATABYTE);
						OutLine[FC_OPERANDS] = FormatOperands(MC_DATABYTE);
						OutLine[FC_COMMENT] = FormatComments(MC_DATABYTE) + " -- Erroneous Indirect Stub";
						outFile << MakeOutputLine(OutLine) << "\n";
						break;
					}

					if (m_bDataOpBytesFlag) OutLine[FC_OPBYTES] = FormatOpBytes();
					OutLine[FC_MNEMONIC] = FormatMnemonic(MC_INDIRECT);
					OutLine[FC_OPERANDS] = FormatOperands(MC_INDIRECT);
					OutLine[FC_COMMENT] = FormatComments(MC_INDIRECT);
					outFile << MakeOutputLine(OutLine) << "\n";
					break;

				default:
					Done = true;
			}
		}

		RetVal = RetVal && WritePostDataSection(outFile, msgFile, errFile);
	}

	return RetVal;
}

bool CDisassembler::WritePostDataSection(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WritePreCodeSection(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WriteCodeSection(std::ostream& outFile, std::ostream *msgFile, std::ostream *errFile)
{
	bool RetVal;
	TStringArray OutLine;
	bool Done;
	unsigned int SavedPC;
	bool bInFunc;
	bool bLastFlag;
	bool bBranchOutFlag;

	ClearOutputLine(OutLine);

	RetVal = false;
	if (WritePreCodeSection(outFile, msgFile, errFile)) {
		RetVal = true;

		bInFunc = false;
		Done = false;
		while ((m_PC < m_Memory->GetMemSize()) && (Done == false) && (RetVal)) {
			bLastFlag = false;
			bBranchOutFlag = false;

			// Check for function start/end flags:
			TAddressMap::const_iterator itrFunction = m_FunctionsTable.find(m_PC);
			if (itrFunction != m_FunctionsTable.end()) {
				switch (itrFunction->second) {
					case FUNCF_HARDSTOP:
					case FUNCF_EXITBRANCH:
					case FUNCF_SOFTSTOP:
						bInFunc = false;
						bLastFlag = true;
						break;

					case FUNCF_BRANCHOUT:
						bBranchOutFlag = true;
						break;

					case FUNCF_BRANCHIN:
						if (bInFunc) {
							RetVal = RetVal && WriteIntraFunctionSep(outFile, msgFile, errFile);
							break;		// Continue if already inside a function (after printing a soft-break)
						}
						// Else, fall-through and setup for new function:
					case FUNCF_ENTRY:
					case FUNCF_INDIRECT:
					case FUNCF_CALL:
						RetVal = RetVal && WritePreFunction(outFile, msgFile, errFile);
						bInFunc = true;
						break;

					default:
						assert(false);			// Unexpected Function Flag!!  Check Code!!
						RetVal = false;
						continue;
				}
			}

			ClearOutputLine(OutLine);
			OutLine[FC_ADDRESS] = FormatAddress(m_PC);

			TLabelTableMap::const_iterator itrLabels = m_LabelTable.find(m_PC);
			if (itrLabels != m_LabelTable.end()) {
				for (unsigned int i=1; i<itrLabels->second.size(); ++i) {
					OutLine[FC_LABEL] = FormatLabel(LC_CODE, itrLabels->second.at(i), m_PC);
					outFile << MakeOutputLine(OutLine) << "\n";
				}
				if (itrLabels->second.size()) OutLine[FC_LABEL] = FormatLabel(LC_CODE, itrLabels->second.at(0), m_PC);
			}

			SavedPC = m_PC;		// Keep a copy of the PC for this line because some calls will be incrementing our m_PC
			switch (m_Memory->GetDescriptor(m_PC)) {
				case DMEM_ILLEGALCODE:
					m_OpMemory.clear();
					m_OpMemory.push_back(m_Memory->GetByte(m_PC++));
					OutLine[FC_OPBYTES] = FormatOpBytes();
					OutLine[FC_MNEMONIC] = FormatMnemonic(MC_ILLOP);
					OutLine[FC_OPERANDS] = FormatOperands(MC_ILLOP);
					OutLine[FC_COMMENT] = FormatComments(MC_ILLOP);
					outFile << MakeOutputLine(OutLine) << "\n";
					break;
				case DMEM_CODE:
					// If the following call returns false, that means that we erroneously
					//	detected code in the first pass so instead of throwing an error or
					//	causing problems, we will treat it as an illegal opcode:
					if (ReadNextObj(false, msgFile, errFile) == false) {		// Bumps PC
						// Flag it as illegal and then process it as such:
						m_Memory->SetDescriptor(SavedPC, DMEM_ILLEGALCODE);
						OutLine[FC_OPBYTES] = FormatOpBytes();
						OutLine[FC_MNEMONIC] = FormatMnemonic(MC_ILLOP);
						OutLine[FC_OPERANDS] = FormatOperands(MC_ILLOP);
						OutLine[FC_COMMENT] = FormatComments(MC_ILLOP);
						outFile << MakeOutputLine(OutLine) << "\n";
						break;
					}
					OutLine[FC_OPBYTES] = FormatOpBytes();
					OutLine[FC_MNEMONIC] = FormatMnemonic(MC_OPCODE);
					OutLine[FC_OPERANDS] = FormatOperands(MC_OPCODE);
					OutLine[FC_COMMENT] = FormatComments(MC_OPCODE);
					outFile << MakeOutputLine(OutLine) << "\n";
					break;
				default:
					Done = true;
			}

			if (bBranchOutFlag) {
				itrFunction = m_FunctionsTable.find(m_PC);
				if (itrFunction != m_FunctionsTable.end()) {
					switch (itrFunction->second) {
						case FUNCF_ENTRY:
						case FUNCF_INDIRECT:
						case FUNCF_CALL:
							bInFunc = false;
							bLastFlag = true;
							break;
					}
				} else {
					bInFunc = false;
					bLastFlag = true;
				}
			}

			if (bLastFlag) {
				itrFunction = m_FunctionsTable.find(m_PC);
				if (itrFunction != m_FunctionsTable.end()) {
					switch (itrFunction->second) {
						case FUNCF_BRANCHIN:
							bLastFlag = false;
							bInFunc = true;
							break;
					}
				}
			}

			if (/*(bInFunc) || */ (bLastFlag)) {
				RetVal = RetVal & WritePostFunction(outFile, msgFile, errFile);
			}
		}

		RetVal = RetVal && WritePostCodeSection(outFile, msgFile, errFile);
	}

	return RetVal;
}

bool CDisassembler::WritePostCodeSection(std::ostream& /* outFile */, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Don't do anything by default
{
	return true;
}

bool CDisassembler::WritePreFunction(std::ostream& outFile, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Default is separator bar
{
	TStringArray OutLine;

	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(m_PC);
	outFile << MakeOutputLine(OutLine) << "\n";
	OutLine[FC_LABEL] = GetCommentStartDelim();
	OutLine[FC_LABEL] += " ";
	for (int i=(GetFieldWidth(FC_LABEL)+
			GetFieldWidth(FC_MNEMONIC)+
			GetFieldWidth(FC_OPERANDS)); i; i--) OutLine[FC_LABEL] += "=";
	OutLine[FC_LABEL] += " ";
	OutLine[FC_LABEL] += GetCommentEndDelim();
	outFile << MakeOutputLine(OutLine) << "\n";

	return true;
}

bool CDisassembler::WriteIntraFunctionSep(std::ostream& outFile, std::ostream * /* msgFile */, std::ostream * /* errFile */)	// Default is separator bar
{
	TStringArray OutLine;

	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(m_PC);
	OutLine[FC_LABEL] = GetCommentStartDelim();
	OutLine[FC_LABEL] += " ";
	for (int i=(GetFieldWidth(FC_LABEL)+
			GetFieldWidth(FC_MNEMONIC)+
			GetFieldWidth(FC_OPERANDS)); i; i--) OutLine[FC_LABEL] += "-";
	OutLine[FC_LABEL] += " ";
	OutLine[FC_LABEL] += GetCommentEndDelim();
	outFile << MakeOutputLine(OutLine) << "\n";

	return true;
}

bool CDisassembler::WritePostFunction(std::ostream& outFile, std::ostream * /* msgFile */, std::ostream * /* errFile */)		// Default is separator bar
{
	TStringArray OutLine;

	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(m_PC);
	OutLine[FC_LABEL] = GetCommentStartDelim();
	OutLine[FC_LABEL] += " ";
	for (int i=(GetFieldWidth(FC_LABEL)+
			GetFieldWidth(FC_MNEMONIC)+
			GetFieldWidth(FC_OPERANDS)); i; i--) OutLine[FC_LABEL] += "=";
	OutLine[FC_LABEL] += " ";
	OutLine[FC_LABEL] += GetCommentEndDelim();
	outFile << MakeOutputLine(OutLine) << "\n";
	ClearOutputLine(OutLine);
	OutLine[FC_ADDRESS] = FormatAddress(m_PC);
	outFile << MakeOutputLine(OutLine) << "\n";

	return true;
}

int CDisassembler::GetFieldWidth(FIELD_CODE nFC)
{
	switch (nFC) {
		case FC_ADDRESS:	return CALC_FIELD_WIDTH(8);
		case FC_OPBYTES:	return CALC_FIELD_WIDTH(12);
		case FC_LABEL:		return CALC_FIELD_WIDTH(14);
		case FC_MNEMONIC:	return CALC_FIELD_WIDTH(8);
		case FC_OPERANDS:	return CALC_FIELD_WIDTH(44);
		case FC_COMMENT:	return CALC_FIELD_WIDTH(60);
	}
	return 0;
}

std::string CDisassembler::MakeOutputLine(TStringArray& saOutputData)
{
	std::string OutputStr;
	std::string Temp,Temp2;
	std::string Item;
	std::size_t fw;
	std::size_t pos;
	std::size_t tfw;
	std::size_t TempPos;
	std::string OpBytePart;
	std::string CommentPart;
	TStringArray WrapSave;
	int Toss;
	bool LabelBreak;
	std::string SaveLabel;

	// This function will "wrap" the FC_OPBYTES and FC_COMMENT fields and create a
	//	result that spans multiple lines if they are longer than the field width.
	//	Wrapping is first attempted via white-space and/or one of ",;:.!?" symbols.  If
	//	that fails, the line is truncated at the specified length.  All other
	//	fields are not wrapped.  Note that embedded tabs count as 1 character for the
	//	wrapping mechanism!  Also, a '\n' can be used in the FC_COMMENT field to force
	//	a break.  All other fields should NOT have a '\n' character!
	//
	//	A '\v' (vertical tab or 0x0B) at the end of FC_LABEL will cause the label to
	//	appear on a line by itself -- the '\v' for labels should appear only at the end
	//	of the label -- not in the middle of it!.
	//

	OpBytePart = "";
	CommentPart = "";
	LabelBreak = false;

	OutputStr = "";
	pos = 0;
	tfw = 0;
	fw = 0;
	for (unsigned int i=0; i<saOutputData.size(); ++i) {
		Item = saOutputData[i];

		tfw += fw;
		fw = GetFieldWidth((FIELD_CODE) i);

		if ((m_bAddrFlag == false) && (i == FC_ADDRESS)) {
			pos += fw;
			continue;
		}
		if ((m_bOpcodeFlag == false) && (i == FC_OPBYTES)) {
			pos += fw;
			continue;
		}

		if (i == FC_LABEL) {			// Check for Label Break:
			if (Item.find('\v') != std::string::npos) {
				while (Item.find('\v') != std::string::npos) {
					Item = Item.substr(0, Item.find('\v')) + Item.substr(Item.find('\v')+1);
				}
				SaveLabel = Item;
				Item.clear();
				LabelBreak = true;
			}
		}

		if (i == FC_OPBYTES) {			// Check OpBytes "wrap"
			if (Item.size() > fw) {
				Temp = Item.substr(0, fw);
				TempPos = Temp.find_last_of(" \t,;:.!?");
				if (TempPos != std::string::npos) {
					Toss = ((Temp.find_last_of(" \t")==TempPos) ? 1 : 0);
					Temp = Item.substr(0, TempPos + 1 - Toss);	// Throw ' ' and '\t' away
					OpBytePart = Item.substr(TempPos + Toss);
					Item = Temp;
				} else {
					OpBytePart = Item.substr(fw+1);
					Item = Item.substr(0, fw);
				}
			}
		}
		if (i == FC_COMMENT) {			// Check comment "wrap"
			Temp = GetCommentStartDelim() + " " + Item + " " + GetCommentEndDelim();
			Temp2 = GetCommentStartDelim() + "  " + GetCommentEndDelim();
			if ((Temp.size() > fw) || (Temp.find('\n') != std::string::npos)) {
				Temp = Item.substr(0, fw - Temp2.size());
				TempPos = Temp.find_last_of(" \n\t,;:.!?");
				if (TempPos != std::string::npos) {
					Toss = ((Temp.find_last_of(" \n\t")==TempPos) ? 1 : 0);
					Temp = Item.substr(0, TempPos + 1 - Toss);	// Throw ' ' and '\t' away
					CommentPart = "  " + Item.substr(TempPos+1 + Toss);
					Item = Temp;
				} else {
					CommentPart = "  " + Item.substr(fw+1-Temp2.size());
					Item = Item.substr(0, fw-Temp2.size());
				}
			}
		}

		if (i == FC_COMMENT) {
			if (!Item.empty())
				Item = GetCommentStartDelim() + " " + Item + " " + GetCommentEndDelim();
		}

		if (m_bTabsFlag) {
			while (pos < tfw) {
				if (m_nTabWidth != 0) {
					while ((tfw - pos) % m_nTabWidth) {
						OutputStr += " ";
						pos++;
					}
					while ((tfw - pos) / m_nTabWidth) {
						OutputStr += "\t";
						pos += m_nTabWidth;
					}
				} else {
					OutputStr += " ";
					pos++;
				}
			}
			OutputStr += Item;
		} else {
			Temp = "";
			for (int j=0; j<m_nTabWidth; j++) Temp += " ";
			while (Item.find('\t') != std::string::npos) {
				TempPos = Item.find('\t');
				Item = Item.substr(0, TempPos) + Temp + Item.substr(TempPos+1);
			}
			while (pos < tfw) {
				OutputStr += " ";
				pos++;
			}
			OutputStr += Item;
		}
		pos += Item.size();
		if (pos >= (tfw+fw)) pos = tfw+fw-1;		// Sub 1 to force at least 1 space between fields
	}

	// Remove all extra white space on right-hand side:
	rtrim(OutputStr);

	if ((!OpBytePart.empty()) || (!CommentPart.empty()) || (LabelBreak)) {
		// Save data:
		WrapSave = saOutputData;
		if (saOutputData.size() < NUM_FIELD_CODES)
			for (unsigned int i=saOutputData.size(); i<NUM_FIELD_CODES; ++i) saOutputData.push_back(std::string());

		if (LabelBreak) {
			saOutputData[FC_OPBYTES] = "";
			saOutputData[FC_LABEL] = SaveLabel;
			saOutputData[FC_MNEMONIC] = "";
			saOutputData[FC_OPERANDS] = "";
			saOutputData[FC_COMMENT] = "";
			OutputStr = MakeOutputLine(saOutputData) + "\n" + OutputStr;	// Call recursively
		}
		if ((!OpBytePart.empty()) || (!CommentPart.empty())) {
			saOutputData[FC_OPBYTES] = OpBytePart;
			saOutputData[FC_LABEL] = "";
			saOutputData[FC_MNEMONIC] = "";
			saOutputData[FC_OPERANDS] = "";
			saOutputData[FC_COMMENT] = CommentPart;
			OutputStr += "\n";
			OutputStr += MakeOutputLine(saOutputData);		// Call recursively
		}

		// Restore data:
		saOutputData = WrapSave;
	}

	return OutputStr;
}

void CDisassembler::ClearOutputLine(TStringArray& saOutputData)
{
	saOutputData.clear();
	saOutputData.reserve(NUM_FIELD_CODES);
	for (unsigned int i=0; i<NUM_FIELD_CODES; ++i) saOutputData.push_back(std::string());
}
<file_sep>/programs/funcanal/FuncView/OutputView.cpp
// OutputView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: OutputView.cpp,v $
// Revision 1.1  2003/09/13 05:45:47  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "FuncViewPrjDoc.h"
#include "OutputView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COutputViewFile

COutputViewFile::COutputViewFile(COutputView &rOutputView)
		: m_rOutputView(rOutputView), m_bEraseOnNextWrite(TRUE)
{
}

COutputViewFile::~COutputViewFile()
{
}

#ifdef _DEBUG
void COutputViewFile::AssertValid() const
{
	CFile::AssertValid();
}

void COutputViewFile::Dump(CDumpContext& dc) const
{
	CFile::Dump(dc);
}
#endif

DWORD COutputViewFile::GetPosition() const
{
	return 0;		// Always a zero-length file
}

BOOL COutputViewFile::GetStatus(CFileStatus& rStatus) const
{
	rStatus.m_ctime = 0;
	rStatus.m_mtime = 0;
	rStatus.m_atime = 0;
	rStatus.m_size = 0;
	rStatus.m_attribute = normal;
	rStatus.m_szFullName[0] = '\0';
	return TRUE;
}

LONG COutputViewFile::Seek(LONG lOff, UINT nFrom)
{
	return 0;		// All offsets are legal, but we are zero length
}

void COutputViewFile::SetLength(DWORD dwNewLen)
{
	// Do nothing
}

UINT COutputViewFile::Read(void* lpBuf, UINT nCount)
{
	return 0;		// This is an output only file
}

void COutputViewFile::Write(const void* lpBuf, UINT nCount)
{
	CEdit &theEdit = m_rOutputView.GetEditCtrl();

	if (m_bEraseOnNextWrite) {
		m_bEraseOnNextWrite = FALSE;

		theEdit.SetWindowText("");
	}

	CString strTemp;
	LPTSTR pBuffer = strTemp.GetBuffer(nCount + 1);
	memcpy(pBuffer, lpBuf, nCount);
	strTemp.ReleaseBuffer(nCount);

	UINT nLen = m_rOutputView.GetBufferLength();

	theEdit.SetSel(nLen, nLen, TRUE);
	theEdit.ReplaceSel(strTemp);

	nLen = m_rOutputView.GetBufferLength();
	theEdit.SetSel(nLen, nLen, FALSE);
}

void COutputViewFile::Abort()
{
	m_bEraseOnNextWrite = TRUE;
}

void COutputViewFile::Flush()
{
	// Do nothing
}

void COutputViewFile::Close()
{
	m_bEraseOnNextWrite = TRUE;
}

CFile* COutputViewFile::Duplicate() const
{
	AfxThrowNotSupportedException();
	return NULL;
}

void COutputViewFile::LockRange(DWORD dwPos, DWORD dwCount)
{
	AfxThrowNotSupportedException();
}

void COutputViewFile::UnlockRange(DWORD dwPos, DWORD dwCount)
{
	AfxThrowNotSupportedException();
}


/////////////////////////////////////////////////////////////////////////////
// COutputView

IMPLEMENT_DYNCREATE(COutputView, CEditView)

COutputView::COutputView()
{
	m_pOutputViewFile = NULL;
	m_fntOutput.CreatePointFont(100, "Courier New");
}

COutputView::~COutputView()
{
	if (m_pOutputViewFile) {
		delete m_pOutputViewFile;
		m_pOutputViewFile = NULL;
	}
}


BEGIN_MESSAGE_MAP(COutputView, CEditView)
	//{{AFX_MSG_MAP(COutputView)
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// COutputView diagnostics

#ifdef _DEBUG
void COutputView::AssertValid() const
{
	CEditView::AssertValid();
}

void COutputView::Dump(CDumpContext& dc) const
{
	CEditView::Dump(dc);
}

CFuncViewPrjDoc* COutputView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// COutputView message handlers

void COutputView::OnInitialUpdate() 
{
	CEdit &theEdit = GetEditCtrl();

	m_pOutputViewFile = new COutputViewFile(*this);

	theEdit.SetFont(&m_fntOutput);
	theEdit.SetReadOnly();
	theEdit.SetWindowText(GetDocument()->GetOutputText());

	UINT nLen = GetBufferLength();
	theEdit.SetSel(nLen-1, nLen, FALSE);
	theEdit.SetSel(nLen, nLen, FALSE);

	CEditView::OnInitialUpdate();
}

void COutputView::OnDestroy() 
{
	CEdit &theEdit = GetEditCtrl();

	theEdit.GetWindowText(GetDocument()->GetOutputText());

	CEditView::OnDestroy();
}

<file_sep>/programs/funcanal/FuncView/CompDiffEditView.h
// CompDiffEditView.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: CompDiffEditView.h,v $
// Revision 1.1  2003/09/13 05:45:37  dewhisna
// Initial Revision
//
//

#if !defined(AFX_COMPDIFFEDITVIEW_H__1A399480_51DB_4106_8311_DE331ED9A3A0__INCLUDED_)
#define AFX_COMPDIFFEDITVIEW_H__1A399480_51DB_4106_8311_DE331ED9A3A0__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "FuncViewPrjDoc.h"

/////////////////////////////////////////////////////////////////////////////
// CCompDiffEditView view

class CCompDiffEditView : public CEditView
{
protected:
	CCompDiffEditView();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(CCompDiffEditView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();

protected:
	CFont m_fntEditor;

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CCompDiffEditView)
	public:
	virtual void OnInitialUpdate();
	protected:
	virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CCompDiffEditView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

	// Generated message map functions
protected:
	//{{AFX_MSG(CCompDiffEditView)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in CompDiffEditView.cpp
inline CFuncViewPrjDoc* CCompDiffEditView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_COMPDIFFEDITVIEW_H__1A399480_51DB_4106_8311_DE331ED9A3A0__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/ChildFrm3.h
// ChildFrm3.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm3.h,v $
// Revision 1.1  2003/09/13 05:45:33  dewhisna
// Initial Revision
//
//

#if !defined(AFX_CHILDFRM3_H__A86FCD44_79E0_4642_8520_2C75C5B83EF6__INCLUDED_)
#define AFX_CHILDFRM3_H__A86FCD44_79E0_4642_8520_2C75C5B83EF6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ChildFrmBase.h"

/////////////////////////////////////////////////////////////////////////////
// CChildFrame3 frame

class CChildFrame3 : public CChildFrameBase
{
	DECLARE_DYNCREATE(CChildFrame3)
protected:
	CChildFrame3();           // protected constructor used by dynamic creation

// Attributes
public:

protected:
	CSplitterWnd m_wndSplitter;

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CChildFrame3)
	protected:
	virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CChildFrame3();

	// Generated message map functions
	//{{AFX_MSG(CChildFrame3)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM3_H__A86FCD44_79E0_4642_8520_2C75C5B83EF6__INCLUDED_)
<file_sep>/programs/funcanal/funcdesc.h
// funcdesc.h: interface for the CFuncDesc, CFuncDescFile, and CFuncObject classes.
//
// $Log: funcdesc.h,v $
// Revision 1.4  2003/09/13 05:38:48  dewhisna
// Added Read/Write File support.  Added output options on output line creation
// for function diff and added returning of match percentage.  Added callback
// function for read operation feedback.  Enhanced symbol map manipulation.
//
// Revision 1.3  2003/02/09 06:59:57  dewhisna
// Split comparison logic from Function File I/O
//
// Revision 1.2  2002/09/15 22:54:03  dewhisna
// Added Symbol Table comparison support
//
// Revision 1.1  2002/07/01 05:50:01  dewhisna
// Initial Revision
//
//

#if !defined(AFX_FUNCDESC_H__E6CF1B55_6B17_4909_A17F_B572ED0ED0E6__INCLUDED_)
#define AFX_FUNCDESC_H__E6CF1B55_6B17_4909_A17F_B572ED0ED0E6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <MemClass.h>
#include "funccomp.h"

// Foward Declarations:
class CFuncDesc;
class CFuncDescFile;
class CSymbolMap;


#define CALC_FIELD_WIDTH(x) x

//////////////////////////////////////////////////////////////////////
// Global Functions
//////////////////////////////////////////////////////////////////////

extern CString PadString(LPCTSTR pszString, int nWidth);


//////////////////////////////////////////////////////////////////////
// Callback Functions
//////////////////////////////////////////////////////////////////////

// Function Analysis Progress Callback -- Used in functions that take
//		a while to do processing (like reading a file).  Passes
//		current progress position, maximum progress value, a flag
//		indicating if the user/client can currently cancel operation,
//		and a client defined lParam.  Returns True/False Cancel Status.
//		True=Cancel, False=Continue.  If progress indexes aren't supported
//		then nProgressPos will always be 0 and nProgressMax always 1.
typedef BOOL (CALLBACK * LPFUNCANALPROGRESSCALLBACK)(int nProgressPos, int nProgressMax, BOOL bAllowCancel, LPARAM lParam);


//////////////////////////////////////////////////////////////////////
// CFuncObject Class
//////////////////////////////////////////////////////////////////////
//		This specifies a pure virtual base class for defining
//		Function Objects:
class CFuncObject : public CObject
{
public:
	CFuncObject(CFuncDescFile &ParentFuncFile, CFuncDesc &ParentFunc, CStringArray &argv);
	virtual ~CFuncObject();

	virtual BOOL IsExactMatch(CFuncObject *pObj);

	virtual BOOL AddLabel(LPCTSTR pszLabel);

	DWORD	GetRelFuncAddress();
	DWORD	GetAbsAddress();
	int		GetLabelCount();
	CString	GetLabel(int nIndex);
	CString	GetBytes();
	int		GetByteCount();

	virtual CString ExportToDiff() = 0;
	virtual void ExportToDiff(CStringArray &anArray) = 0;

	virtual CString CreateOutputLine(DWORD nOutputOptions = 0) = 0;

	virtual void GetSymbols(CStringArray &aSymbolArray);	// Returns specially encoded symbol array (see implementation comments)

	// The following define field positions for obtaining field widths from overrides.
	//	Additional entries can be added on overrides, but this order should NOT change
	//	in order to maintain backward compatibility at all times:
	#define NUM_FIELD_CODES 6
	enum FIELD_CODE { FC_ADDRESS, FC_OPBYTES, FC_LABEL, FC_MNEMONIC, FC_OPERANDS, FC_COMMENT };

	static int GetFieldWidth(FIELD_CODE nFC);

protected:
	CFuncDescFile &m_ParentFuncFile;
	CFuncDesc &m_ParentFunc;

	DWORD	m_dwRelFuncAddress;			// Address of object relative to function start
	DWORD	m_dwAbsAddress;				// Absolute Address of object
	CStringArray	m_LabelTable;		// Labels assigned to this object
	CByteArray	m_Bytes;				// Array of bytes for this object
};

//////////////////////////////////////////////////////////////////////
// CFuncAsmInstObject Class
//////////////////////////////////////////////////////////////////////
//		This class specifies an assembly instruction object
class CFuncAsmInstObject : public CFuncObject
{
public:
	CFuncAsmInstObject(CFuncDescFile &ParentFuncFile, CFuncDesc &ParentFunc, CStringArray &argv);
	virtual ~CFuncAsmInstObject();

	virtual CString ExportToDiff();
	virtual void ExportToDiff(CStringArray &anArray);

	virtual CString CreateOutputLine(DWORD nOutputOptions = 0);

	virtual void GetSymbols(CStringArray &aSymbolArray);	// Returns specially encoded symbol array (see implementation comments)

	CString	GetOpCodeBytes();
	int		GetOpCodeByteCount();

	CString	GetOperandBytes();
	int		GetOperandByteCount();

protected:
	CByteArray m_OpCodeBytes;			// Array of OpCode Bytes for this instruction
	CByteArray m_OperandBytes;			// Array of Operand Bytes for ths instruction
	CString	m_strDstOperand;			// Encoded Destination Operand
	CString	m_strSrcOperand;			// Encoded Source Operand
	CString	m_strOpCodeText;			// Textual OpCode mnemonic
	CString	m_strOperandText;			// Textual Operands
};

//////////////////////////////////////////////////////////////////////
// CFuncDataByteObject Class
//////////////////////////////////////////////////////////////////////
//		This class specifies a function embedded data byte object
class CFuncDataByteObject : public CFuncObject
{
public:
	CFuncDataByteObject(CFuncDescFile &ParentFuncFile, CFuncDesc &ParentFunc, CStringArray &argv);
	virtual ~CFuncDataByteObject();

	virtual CString ExportToDiff();
	virtual void ExportToDiff(CStringArray &anArray);

	virtual CString CreateOutputLine(DWORD nOutputOptions = 0);
};

//////////////////////////////////////////////////////////////////////
// CFuncDesc Class
//////////////////////////////////////////////////////////////////////
//		This specifies exactly one function as an array of CFuncObject
//		objects:
class CFuncDesc : public CTypedPtrArray<CObArray, CFuncObject *>
{
public:
	CFuncDesc(DWORD nAddress, LPCTSTR pszNames);
	virtual ~CFuncDesc();

	void FreeAll();

	virtual BOOL AddName(DWORD nAddress, LPCTSTR pszLabel);
	virtual CString GetMainName();
	virtual DWORD GetMainAddress();

	virtual BOOL AddLabel(DWORD nAddress, LPCTSTR pszLabel);
	virtual BOOL AddrHasLabel(DWORD nAddress);
	virtual CString GetPrimaryLabel(DWORD nAddress);
	virtual CStringArray *GetLabelList(DWORD nAddress);

	virtual DWORD GetFuncSize();		// Returns size of function in byte counts (used for address calculation)

	virtual CString ExportToDiff();
	virtual void ExportToDiff(CStringArray &anArray);

	int Add(CFuncObject *anObj);


	// Warning: This object supports ADDing only!  Removing an item does NOT remove labels
	//			that have been added nor decrement the function size!  To modify a function
	//			description, create a new function object with only the new elements desired!!
	//			This has been done to improve speed efficiency!

protected:
	DWORD m_dwMainAddress;		// Main Address is the address defined at instantiation time.  Additional relocated declarations might be defined in the name list
	DWORD m_dwFunctionSize;		// Count of bytes in function -- used to calculate addressing inside the function

	// Note: The File's Label Table only contains those labels defined
	//			internally in this function and may not directly
	//			correspond to that of the file level.  These might
	//			contain 'L' labels.
	CMap<DWORD, DWORD, CStringArray*, CStringArray*> m_FuncNameTable;	// Table of names for this function.  First entry is typical default
	CMap<DWORD, DWORD, CStringArray*, CStringArray*> m_LabelTable;	// Table of labels in this function.  First entry is typical default
};

//////////////////////////////////////////////////////////////////////
// CFuncDescFile Class
//////////////////////////////////////////////////////////////////////
//		This specifies all of the information from a single Func
//		Description File.  It contains a CFuncDescArray of all of
//		the functions in the file, but also contains the file mapping
//		and label information:
class CFuncDescFile : public CObject
{
public:
	CFuncDescFile();
	virtual ~CFuncDescFile();

	void FreeAll();

	virtual BOOL ReadFuncDescFile(CFile& inFile, CFile *msgFile = NULL, CFile *errFile = NULL, int nStartLineCount = 0);			// Read already open control file 'infile', outputs messages to 'msgFile' and errors to 'errFile', nStartLineCount = initial line counter value

	virtual BOOL AddLabel(DWORD nAddress, LPCTSTR pszLabel);
	virtual BOOL AddrHasLabel(DWORD nAddress);
	virtual CString GetPrimaryLabel(DWORD nAddress);
	virtual CStringArray *GetLabelList(DWORD nAddress);

	virtual int GetFuncCount();
	virtual CFuncDesc *GetFunc(int nIndex);

	CString GetFuncPathName();
	CString GetFuncFileName();

	virtual BOOL IsROMMemAddr(DWORD nAddress);
	virtual BOOL IsRAMMemAddr(DWORD nAddress);
	virtual BOOL IsIOMemAddr(DWORD nAddress);

	virtual SetProgressCallback(LPFUNCANALPROGRESSCALLBACK pfnCallback, LPARAM lParam)
			{ m_pfnProgressCallback = pfnCallback;  m_lParamProgressCallback = lParam; }

protected:
	CString		m_strFilePathName;
	CString		m_strFileName;

	TMemRange	m_ROMMemMap;		// Mapping of ROM memory
	TMemRange	m_RAMMemMap;		// Mapping of RAM memory
	TMemRange	m_IOMemMap;			// Mapping of memory mapped I/O

	LPFUNCANALPROGRESSCALLBACK m_pfnProgressCallback;
	LPARAM		m_lParamProgressCallback;

	// Note: The File's Label Table only contains those labels defined
	//			at the file level by "!" entries.  NOT those down at the
	//			individual function level.  Specifically it doesn't
	//			include 'L' names.
	CMap<DWORD, DWORD, CStringArray*, CStringArray*> m_LabelTable;	// Table of labels.  First entry is typical default
	CTypedPtrArray<CObArray, CFuncDesc*> m_Functions;	// Array of functions in the file

private:
	CMap<CString, LPCTSTR, WORD, WORD>	ParseCmdsOP1;	// Used internally to store control file commands
};

//////////////////////////////////////////////////////////////////////
// CFuncDescFileArray Class
//////////////////////////////////////////////////////////////////////
//		This specifies a cluster of Func Definition Files as an array
//		of CFuncDescFile Objects.
class CFuncDescFileArray : public CTypedPtrArray<CObArray, CFuncDescFile *>
{
public:
	CFuncDescFileArray();
	virtual ~CFuncDescFileArray();

	void FreeAll();

	virtual int GetFuncCount();

	virtual double CompareFunctions(FUNC_COMPARE_METHOD nMethod,
									int nFile1Ndx, int nFile1FuncNdx,
									int nFile2Ndx, int nFile2FuncNdx,
									BOOL bBuildEditScript);
	virtual CString DiffFunctions(FUNC_COMPARE_METHOD nMethod,
									int nFile1Ndx, int nFile1FuncNdx,
									int nFile2Ndx, int nFile2FuncNdx,
									DWORD nOutputOptions,
									double &nMatchPercent,
									CSymbolMap *pSymbolMap = NULL);

	virtual SetProgressCallback(LPFUNCANALPROGRESSCALLBACK pfnCallback, LPARAM lParam)
			{ m_pfnProgressCallback = pfnCallback;  m_lParamProgressCallback = lParam; }

protected:
	LPFUNCANALPROGRESSCALLBACK m_pfnProgressCallback;
	LPARAM		m_lParamProgressCallback;
};


//////////////////////////////////////////////////////////////////////
// CSymbolMap Class
//////////////////////////////////////////////////////////////////////
//		This class stores mapping between two sets of functions by
//		hashing and storing address accesses and finding highest
//		hit matches.
class CSymbolMap : public CObject
{
public:
	CSymbolMap();
	virtual ~CSymbolMap();

	void FreeAll();
	BOOL IsEmpty();

	void AddObjectMapping(CFuncObject &aLeftObject, CFuncObject &aRightObject);

	void GetLeftSideCodeSymbolList(CStringArray &anArray);		// Returns sorted list of left-side code symbols
	void GetRightSideCodeSymbolList(CStringArray &anArray);		// Returns sorted list of right-side code symbols
	void GetLeftSideDataSymbolList(CStringArray &anArray);		// Returns sorted list of left-side data symbols
	void GetRightSideDataSymbolList(CStringArray &anArray);		// Returns sorted list of right-side data symbols

	DWORD GetLeftSideCodeHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray);		// Returns sorted array of target hit symbols and corresponding counts, function returns total hit count
	DWORD GetRightSideCodeHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray);	// Returns sorted array of target hit symbols and corresponding counts, function returns total hit count
	DWORD GetLeftSideDataHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray);		// Returns sorted array of target hit symbols and corresponding counts, function returns total hit count
	DWORD GetRightSideDataHitList(LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray);	// Returns sorted array of target hit symbols and corresponding counts, function returns total hit count

private:
	void GetSymbolList(CMap<CString, LPCTSTR, CStringArray*, CStringArray*> &mapSymbolArrays,
						CStringArray &anArray);
	DWORD GetHitList(CMap<CString, LPCTSTR, CStringArray*, CStringArray*> &mapSymbolArrays,
						LPCTSTR aSymbol, CStringArray &aSymbolArray, CDWordArray &aHitCountArray);

//	void SortStringArray(CStringArray &aStringArray);
//	void SortStringDWordArray(CStringArray &aStringArray, CDWordArray &aDWordArray);

protected:
	void AddLeftSideCodeSymbol(LPCTSTR aLeftSymbol, LPCTSTR aRightSymbol);
	void AddRightSideCodeSymbol(LPCTSTR aRightSymbol, LPCTSTR aLeftSymbol);
	void AddLeftSideDataSymbol(LPCTSTR aLeftSymbol, LPCTSTR aRightSymbol);
	void AddRightSideDataSymbol(LPCTSTR aRightSymbol, LPCTSTR aLeftSymbol);

	CMap<CString, LPCTSTR, CStringArray*, CStringArray*> m_LeftSideCodeSymbols;
	CMap<CString, LPCTSTR, CStringArray*, CStringArray*> m_RightSideCodeSymbols;
	CMap<CString, LPCTSTR, CStringArray*, CStringArray*> m_LeftSideDataSymbols;
	CMap<CString, LPCTSTR, CStringArray*, CStringArray*> m_RightSideDataSymbols;
};




#endif // !defined(AFX_FUNCDESC_H__E6CF1B55_6B17_4909_A17F_B572ED0ED0E6__INCLUDED_)

<file_sep>/programs/funcanal/FuncView/SymbolMapTreeView.cpp
// SymbolMapTreeView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: SymbolMapTreeView.cpp,v $
// Revision 1.1  2003/09/13 05:45:50  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "SymbolMapTreeView.h"

#include "FuncViewPrjDoc.h"
#include "../funcdesc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapTreeView

IMPLEMENT_DYNCREATE(CSymbolMapTreeView, CTreeView)

CSymbolMapTreeView::CSymbolMapTreeView()
{
}

CSymbolMapTreeView::~CSymbolMapTreeView()
{
}


BEGIN_MESSAGE_MAP(CSymbolMapTreeView, CTreeView)
	//{{AFX_MSG_MAP(CSymbolMapTreeView)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapTreeView diagnostics

#ifdef _DEBUG
void CSymbolMapTreeView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CSymbolMapTreeView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CFuncViewPrjDoc* CSymbolMapTreeView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapTreeView message handlers

void CSymbolMapTreeView::OnInitialUpdate() 
{
	CTreeCtrl &theTree = GetTreeCtrl();

	theTree.ModifyStyle(0, TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT |
							TVS_SHOWSELALWAYS, SWP_NOACTIVATE);


	// Call default which will call OnUpdate which will call FillSymbolMapList:
	CTreeView::OnInitialUpdate();
}

void CSymbolMapTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

	switch (lHint) {
		case 0:				// Normal Update
			FillSymbolMapList();
			break;

		case SYMBOL_MAP_ALL:
			FillSymbolMapList();
			break;

		case SYMBOL_MAP_LEFT_CODE:
		case SYMBOL_MAP_RIGHT_CODE:
		case SYMBOL_MAP_LEFT_DATA:
		case SYMBOL_MAP_RIGHT_DATA:
			break;
	}


	if ((lHint >= FILESET_TYPE_BASE) && (lHint <= FILESET_TYPE_LAST)) {
		// FILESET_TYPE_BASE+nFileSet = Document Fileset Function update (pHint = &CFuncViewFuncRef)
	}

	if ((lHint >= SYMBOL_MAP_TYPE_BASE) && (lHint <= SYMBOL_MAP_TYPE_LAST)) {
		// SYMBOL_MAP_TYPE_BASE+nSymbolMapType = Symbol Map update (pHint = &LPCTSTR)
	}
}

void CSymbolMapTreeView::FillSymbolMapList()
{
	CTreeCtrl &theTree = GetTreeCtrl();
	theTree.DeleteAllItems();

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	HTREEITEM hLeftCode = theTree.InsertItem("Left-Side Code Symbols");
	HTREEITEM hRightCode = theTree.InsertItem("Right-Side Code Symbols");
	HTREEITEM hLeftData = theTree.InsertItem("Left-Side Data Symbols");
	HTREEITEM hRightData = theTree.InsertItem("Right-Side Data Symbols");

	if ((hLeftCode == NULL) ||
		(hRightCode == NULL) ||
		(hLeftData == NULL) ||
		(hRightData == NULL)) return;

	theTree.SetItemData(hLeftCode, 1);
	theTree.SetItemData(hRightCode, 2);
	theTree.SetItemData(hLeftData, 3);
	theTree.SetItemData(hRightData, 4);

	CStringArray anArr;
	CSymbolMap &theSymbols = pDoc->GetSymbolMap();

	anArr.RemoveAll();
	theSymbols.GetLeftSideCodeSymbolList(anArr);
	FillSymbolMapSubList(hLeftCode, anArr, SYMBOL_MAP_LEFT_CODE);

	anArr.RemoveAll();
	theSymbols.GetRightSideCodeSymbolList(anArr);
	FillSymbolMapSubList(hRightCode, anArr, SYMBOL_MAP_RIGHT_CODE);

	anArr.RemoveAll();
	theSymbols.GetLeftSideDataSymbolList(anArr);
	FillSymbolMapSubList(hLeftData, anArr, SYMBOL_MAP_LEFT_DATA);

	anArr.RemoveAll();
	theSymbols.GetRightSideDataSymbolList(anArr);
	FillSymbolMapSubList(hRightData, anArr, SYMBOL_MAP_RIGHT_DATA);
}

void CSymbolMapTreeView::FillSymbolMapSubList(HTREEITEM hParent, CStringArray &aSymbolList, DWORD nItemData)
{
	int i;
	HTREEITEM hSymbol;
	CTreeCtrl &theTree = GetTreeCtrl();

	for (i=0; i<aSymbolList.GetSize(); i++) {
		hSymbol = theTree.InsertItem(aSymbolList.GetAt(i), hParent);
		if (hSymbol == NULL) continue;
		theTree.SetItemData(hSymbol, nItemData);
	}

	theTree.Expand(hParent, TVE_EXPAND);
}

void CSymbolMapTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	*pResult = 0;

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	CTreeCtrl &theTree = GetTreeCtrl();
	HTREEITEM hSel = theTree.GetSelectedItem();
	DWORD nSelType = 0;
	CString strSelSymbol;

	if (hSel) {
		nSelType = theTree.GetItemData(hSel);
		strSelSymbol = theTree.GetItemText(hSel);
	}

	if (nSelType >= SYMBOL_MAP_TYPE_BASE) {
		pDoc->UpdateAllViews(this, (LPARAM)nSelType, (!strSelSymbol.IsEmpty() ? (CObject*)LPCTSTR(strSelSymbol) : NULL));
	} else {
		if (nSelType == 0) {
			pDoc->UpdateAllViews(this, (LPARAM)SYMBOL_MAP_ALL, NULL);
		} else {
			pDoc->UpdateAllViews(this, (LPARAM)(SYMBOL_MAP_TYPE_BASE + nSelType), NULL);
		}
	}
}

<file_sep>/programs/m6811dis/dfc.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
      DFC   -- DataFileConverter Class

      This is the C++ object definition for a Data File Converter Object.  The
      Data File Converter object is an object that must be overriden by inherited
      classes to perform the task of reading and writing a data file.  This
      class allows the flexibility of file independacy for file converter programs,
      disassemblers, etc.

	  Author:  <NAME>
      Date:    January 29, 1997

      Written in: Borland C++ 4.52

      Updated: June 22, 1997 to work with both MS Visual C++ 4.0/5.0
				as well as Borland C++.

      Description:

         Each Data File Converter is simply a Read function and a Write
      function, as defined here:

*/

#include <iostream>
#include "dfc.h"
#include "stringhelp.h"
#include "memclass.h"
#include "errmsgs.h"

#include "bindfc.h"
#include "inteldfc.h"
#include "sfiledfc.h"

/////////////////////////////////////////////////////////////////////////////
// CDFCObject Implementation

CDFCObject::CDFCObject()
{

}

CDFCObject::~CDFCObject()
{

}

int CDFCObject::RetrieveFileMapping(std::istream * /*aFile*/, unsigned long NewBase, TMemRange *aRange) const
{
	if (aRange) {
		aRange->PurgeRange();
		aRange->SetStartAddr(NewBase);
		aRange->SetSize(0);
	}
	return(1);
}


/////////////////////////////////////////////////////////////////////////////
// CDFCArray Implementation

CDFCArray *CDFCArray::instance()
{
	static CDFCArray DFCs;
	return &DFCs;
}

CDFCArray::CDFCArray()
	:	std::vector<CDFCObject *>()
{
	static TDFC_Binary binDFC;
	static TDFC_Intel hexDFC;
	static TDFC_SFile motDFC;

	push_back(&binDFC);
	push_back(&hexDFC);
	push_back(&motDFC);
}

CDFCArray::~CDFCArray()
{

}

const CDFCObject *CDFCArray::locateDFC(const std::string &strLibraryName) const
{
	for (unsigned int ndx = 0; ndx < size(); ++ndx) {
		if (compareNoCase(strLibraryName, at(ndx)->GetLibraryName()) == 0) return at(ndx);
	}
	return NULL;
}
<file_sep>/programs/funcanal/FuncView/CompMatrixView.h
// CompMatrixView.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: CompMatrixView.h,v $
// Revision 1.1  2003/09/13 05:45:38  dewhisna
// Initial Revision
//
//

#if !defined(AFX_COMPMATRIXVIEW_H__ECF95B71_7B54_4A0D_95E0_C871FC74DD2F__INCLUDED_)
#define AFX_COMPMATRIXVIEW_H__ECF95B71_7B54_4A0D_95E0_C871FC74DD2F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "GridCtrl.h"

class CFuncViewPrjDoc;

/////////////////////////////////////////////////////////////////////////////
// CCompMatrixView view

class CCompMatrixView : public CView
{
protected:
	CCompMatrixView();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(CCompMatrixView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();

protected:
	CGridCtrl *m_pGridCtrl;

// Operations
public:

protected:
	void FillMatrixHeaders();
	void FillMatrixData(int nSingleRow = -1, int nSingleCol = -1);

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CCompMatrixView)
	public:
	virtual void OnInitialUpdate();
	virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
	protected:
	virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnDraw(CDC* pDC);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CCompMatrixView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

	// Generated message map functions
protected:
	//{{AFX_MSG(CCompMatrixView)
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnSymbolsAdd();
	afx_msg void OnUpdateSymbolsAdd(CCmdUI* pCmdUI);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in CompMatrixView.cpp
inline CFuncViewPrjDoc* CCompMatrixView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_COMPMATRIXVIEW_H__ECF95B71_7B54_4A0D_95E0_C871FC74DD2F__INCLUDED_)
<file_sep>/programs/m6811dis/errmsgs.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
 *    ERRMSGS
 *
 *    This header file defines the acceptable "exception" messages for
 *    errorcode handling.
 *
 *    Author:  <NAME>
 *    Date:    January 28, 1997
 *
 *		Rewrote on July 20, 1997 to handle better exception syntax.
 */

#ifndef ERRMSGS_H
#define ERRMSGS_H

#include <string>

#define THROW_MEMORY_EXCEPTION_ERROR(code) \
	{	_OUT_OF_MEMORY_EXCEPTION.lcode = code; \
		throw (&_OUT_OF_MEMORY_EXCEPTION); }

#define THROW_EXCEPTION_ERROR(cause, code, name) \
	{	throw (new EXCEPTION_ERROR(1, cause, code, name));	}

#define DELETE_EXCEPTION_ERROR(an_error) \
	{	if (an_error->delflag)	\
			delete an_error;	}

class EXCEPTION_ERROR
{
public:
	enum {
		ERR_NONE,
		ERR_OUT_OF_MEMORY,
		ERR_OUT_OF_RANGE,
		ERR_MAPPING_OVERLAP,
		ERR_OPENREAD,
		ERR_OPENWRITE,
		ERR_FILEEXISTS,
		ERR_CHECKSUM,
		ERR_UNEXPECTED_EOF,
		ERR_OVERFLOW,
		ERR_WRITEFAILED,
		ERR_READFAILED
	};

	int	delflag;					// heap delete flag
	int	cause;						// Set to one of the above error codes by construction
	unsigned long	lcode;			// long extended code value, used for passing parameters
	std::string		name_ex;		// extended code name copied by constructor, useful for filenames, etc

	EXCEPTION_ERROR();
	EXCEPTION_ERROR(EXCEPTION_ERROR& anException);
	EXCEPTION_ERROR(int adelflag, const int acause = EXCEPTION_ERROR::ERR_NONE, const unsigned long alcode = 0, const std::string &anexname = std::string());
};

extern EXCEPTION_ERROR _OUT_OF_MEMORY_EXCEPTION;

// class ERR_OUT_OF_MEMORY {};
// class ERR_OUT_OF_RANGE {};
// class ERR_MAPPING_OVERLAP {};
// class ERR_OPENREAD { public: char *filename; };
// class ERR_OPENWRITE {public: char *filename; };
// class ERR_FILEEXISTS {};
// class ERR_CHECKSUM { public: int linenumber; };
// class ERR_UNEXPECTED_EOF {};
// class ERR_OVERFLOW {};
// class ERR_WRITEFAILED {};

#endif
<file_sep>/programs/m6811dis/sfiledfc.cpp
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
	SFileDFC

		This is the C++ Module that contains routines to read and write Motorola
		S-Files, by defining a new derived class DFC_SFILE from the base
		class DataFileConverter.  This module makes use of the MEMCLASS type for
		memory interface.

		Author:	<NAME>
		Date:	February 10, 2000

		Written in: MS Visual C++ 5.0

*/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "sfiledfc.h"



// Motorola format:
//		Sxccaa..aadd....kk
//		where:	S is the record character "S"
//				x=record mode or type (See below)
//				cc=byte count after cc -- unlike Intel where the byte count is ONLY
//							the number of data bytes, this is the count of the
//							number of bytes in the address field, plus the number of
//							bytes in the data field, plus the 1 byte checksum
//				aa..aa=offset address -- Can be 2, 3, or 4 bytes depending on the 'x' type
//				dd....=data bytes
//				kk=checksum = 1's complement of the sum of all bytes in the record
//							starting with 'cc' through the last 'dd'...
//							Total sum (including checkbyte) should equal 0xFF
//
//			Record mode/types:
//				0 = Header character -- this is just a file signon that can contain
//						any desired data...  GM PTP's, for example, use "HDR" in the
//						data field...  The Address field is 2 bytes (4 characters) and
//						is usually 0000 except for Motorola DSP's where it indicates
//						the DSP Memory Space for the s-records that follow, where
//						0001=X, 0002=Y, 0003=L, 0004=P, and 0005=E (DSP only!)
//						This field is optional
//				1 = Data Record with a 2-byte address (aaaa = start address for data in this record)
//				2 = Data Record with a 3-byte address (aaaaaa = start address for data in this record)
//				3 = Data Record with a 4-byte address (aaaaaaaa = start address for data in this record)
//				7 = EOF Record with a 4-byte address (aaaaaaaa = Executable start address for this s-file)
//				8 = EOF Record with a 3-byte address (aaaaaa = Executable start address for this s-file)
//				9 = EOF Record with a 2-byte address (aaaa = Executable start address for this s-file)
//
//		Extensions:
//			S19 = 16-Bit addressing files (ones using S1 and S9 records)
//			S28 = 24-Bit addressing files (ones using S2 and S8 records)
//			S37 = 32-Bit addressing files (ones using S3 and S7 records)
//


// Intel format:
//    ccaaaammdd....kk
//    where: cc=byte count
//           aaaa=offset address
//           mm=mode byte
//           dd=date bytes (there are 'cc' many of 'dd' entries)
//           kk=checksum = sum of ALL hex pairs as bytes (including cc, aaaa, mm, and dd)
//                            Sum (including checkbyte) should equal zero.
//       mm=00 -> normal line
//       mm=01 -> end of file
//       mm=02 -> SBA entry


// RetrieveFileMapping:
//
//    This function reads in an already opened text BINARY file pointed to by
//    'aFile' and generates a TMemRange object that encapsulates the file's
//    contents, offsetted by 'NewBase' (allowing loading of different files
//    to different base addresses).
//
// Author:  <NAME>
// Date:    June 28, 1997
int TDFC_SFile::RetrieveFileMapping(std::istream *aFile, unsigned long NewBase, TMemRange *aRange) const
{
   int   RetVal;

   try {
      RetVal = _ReadDataFile(aFile, NewBase, NULL, aRange, 0);
   }
   catch (EXCEPTION_ERROR*) {
      throw;
   }
   return RetVal;
}


// ReadDataFile:
//
//
// Author:  <NAME>
// Date:    January 29, 1997
int TDFC_SFile::ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, unsigned char aDesc) const
{
   int   RetVal;

   try {
      RetVal = _ReadDataFile(aFile, NewBase, aMemory, NULL, aDesc);
   }
   catch (EXCEPTION_ERROR*) {
      throw;
   }
   return RetVal;
}


// _ReadDataFile:
//
//    This function reads in an already opened text BINARY file pointed to by
//    'aFile' into the MemObject pointed to by 'aMemory' offsetted by
//    'NewBase' (allowing loading of different files to different base
//    address) and setting the corresponding Memory Descriptors to 'aDesc'...
//
//    This function has been updated to a composite function that handles both
//    the reading of the file into memory and simply reading the Mapping.
//    This is a private function called by the regular ReadDataFile and
//    RetrieveFileMapping.  If aMemory is null then memory is not filled.  If
//    aRange is null, the mapping is not generated.  If either or both is
//    non-null, then the corresponding operation is performed.
//
// Author:  <NAME>isnant
// Date:    January 29, 1997
int TDFC_SFile::_ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, TMemRange *aRange, unsigned char aDesc) const
{
   int            RetVal;           // Return Value
   int            LineCount;        // Line Counter
   char           Buff[256];        // Line Buffer
   char           *BufPtr;          // Index into buffer
   unsigned int   SBA;              // Segment Base Address
   unsigned int   NBytes;           // Number of bytes supposed to be on line
   unsigned int   OffsetAddr;       // Offset Address read on line
   unsigned int   i;                // Loop counter
   unsigned int   chksum;           // Running Checksum
   unsigned long  CurrAddr;         // Current Memory Address
   unsigned int   Mode;             // Mode Byte
   unsigned int   TempByte;         // Hex to Decimal conversion storage
   int            EndReached;       // End reached Flag
   int            FirstRange;       // Flag for first range
   int            NeedRangeUpdate;  // Flag for needing to update the range capture
   int            NeedToWriteRange; // Flag for needing to write the range
   unsigned long  StartAddr;        // Current StartAddr of the current Range
   unsigned long  CurrSize;         // Current Size of the current Range

   RetVal=1;
   SBA=0;
   LineCount=0;
   EndReached=0;
   aFile->seekg(0L, std::ios_base::beg);
   FirstRange = 1;
   NeedToWriteRange = 0;
   NeedRangeUpdate = 1; // Force the first update
	StartAddr = 0;
   CurrAddr = 0;
   CurrSize = 0;
   if (aRange!=NULL) {
      // Initialize the range and setup incase there are no real bytes
      aRange->PurgeRange();
      aRange->SetStartAddr(0);
      aRange->SetSize(0);
   }
   while ((!aFile->eof()) && (aFile->peek() != EOF) && (!EndReached)) {
      aFile->getline(Buff, sizeof(Buff));
      if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_UNEXPECTED_EOF, 0, "");
      LineCount++;
      if (Buff[0]==':') {
         sscanf(&Buff[1], "%2X%4X%2X", &NBytes, &OffsetAddr, &Mode);
         chksum=NBytes+(OffsetAddr/256)+(OffsetAddr%256)+Mode;

         if (CurrAddr!=((((unsigned long)SBA)*16)+(unsigned long)OffsetAddr+NewBase))
            NeedRangeUpdate=1;

         if (NeedRangeUpdate) {
            // If we need to update the Range do so, else only update the StartAddr
            if (NeedToWriteRange) {
               // If this is not the first range, add a range
               if ((aRange!=NULL) && (!FirstRange)) {
                  try {
                     aRange->AddRange(StartAddr, CurrSize);
                  }
                  catch (EXCEPTION_ERROR*) {
                     throw;
                  }
               }
               // Else, set the first range
               if ((aRange!=NULL) && (FirstRange)) {
                  aRange->SetStartAddr(StartAddr);
                  aRange->SetSize(CurrSize);
                  FirstRange = 0;
               }
               // Signify we don't need to write it, since we just did
               NeedToWriteRange = 0;
            }

            // Set start of next range, and initialize variables
            StartAddr = (((unsigned long)SBA)*16)+(unsigned long)OffsetAddr+NewBase;
            CurrAddr = StartAddr;
            CurrSize = 0;
            NeedRangeUpdate=0;
         }

         BufPtr=&Buff[9];
         switch (Mode) {
			case 0:  for (i=0; i<NBytes; ++i) {
                        sscanf(BufPtr, "%2X", &TempByte);
                        chksum+=TempByte;
                        if (aMemory) {
                           if (!aMemory->SetByte(CurrAddr, (unsigned char)TempByte)) {
                              THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_OVERFLOW, 0, "");
                           }
                           if (aMemory->GetDescriptor(CurrAddr)!=0) RetVal=0;
                           aMemory->SetDescriptor(CurrAddr, aDesc);
                        }
                        CurrAddr++;
                        CurrSize++;
                        BufPtr+=2;
                        // Any time we add a byte, make sure the range gets updated
                        NeedToWriteRange = 1;
                     }
                     break;
            case 1:  EndReached=1;
                     break;
            case 2:  sscanf(BufPtr, "%4X", &SBA);
                     chksum+=(SBA/256)+(SBA%256);
                     BufPtr+=4;
                     break;
         }
         sscanf(BufPtr, "%2X", &TempByte);
         chksum+=TempByte;
         if ((chksum%256)!=0) {
            THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_CHECKSUM, LineCount, "");
         }
      }
   }
   // Make a final test to see if the range needs to be saved,
   //    This is necessary to save the last range operated upon
   //    in case a pre-mature EOF is encountered.
   if (NeedToWriteRange) {
      // If this is not the first range, add a range
      if ((aRange!=NULL) && (!FirstRange)) {
         try {
            aRange->AddRange(StartAddr, CurrSize);
         }
         catch (EXCEPTION_ERROR*) {
            throw;
         }
      }
      // Else, set the first range
      if ((aRange!=NULL) && (FirstRange)) {
         aRange->SetStartAddr(StartAddr);
         aRange->SetSize(CurrSize);
         FirstRange = 0;
      }
   }
   if (((aFile->eof()) || (aFile->peek() == EOF)) &&
       (!EndReached)) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_UNEXPECTED_EOF, 0, "");
   return(RetVal);
}


// WriteDataFile:
//
//    This function writes to an already opened text BINARY file pointed to by
//    'aFile' from the MemObject pointed to by 'aMemory' and whose Descriptor
//    has a match specified by 'aDesc'.  Matching is done by 'anding' the
//    aDesc value with the descriptor in memory.  If the result is non-zero,
//    the location is written.  Unless, aDesc=0, in which case ALL locations
//    are written regardless of the actual descriptor.  If the aDesc validator
//    computes out as false, then the data is filled according to the FillMode.
//
// Author:  <NAME>
// Date:    January 29, 1997
int TDFC_SFile::WriteDataFile(std::ostream *aFile, TMemRange *aRange, unsigned long NewBase, TMemObject *aMemory,
					 unsigned char aDesc, int UsePhysicalAddr, unsigned int FillMode) const
{
   TMemRange      *CurrRange;       // Range Spanning variable
   int            RetVal;           // Return Value
   int            LineCount;        // Line Counter
   char           TempStr[10];      // Temporary Conversion String
   char           Buff[256];        // Line Buffer
   unsigned int   SBA;              // Segment Base Address
   unsigned int   NBytes;           // Number of bytes supposed to be on line
   unsigned int   OffsetAddr = 0;   // Offset Address read on line
   unsigned int   i;                // Loop counter
   unsigned int   chksum;           // Running Checksum
   unsigned long  BytesLeft;        // Remaining number of bytes to check/write
   unsigned long  CurrAddr;         // Current Logical Memory Address
   unsigned long  RealAddr = 0;     // Current Written Address equivalent
   unsigned int   LowestOffset;     // Lowest Load offset for the file
   unsigned int   LowestFound;      // Flag for finding lowest offset
   unsigned int   TempByte;         // Temp byte used for calculation
   int            NeedNewOffset;    // Flag for needing to write a new offset
   char           WriteBuff[256];   // Used for printing to the output stream
   int            NoFill;           // Flag for no-byte and no-fill

   srand( (unsigned)time( NULL ) );

   CurrRange=aRange;
   RetVal=1;
   SBA=0;
   LineCount=0;
   LowestOffset=0x0000;
   LowestFound=0;

   while (CurrRange!=NULL) {
      CurrAddr=CurrRange->GetStartAddr();
      BytesLeft=CurrRange->GetSize();

      while (BytesLeft) {
         strcpy(Buff, "");
         NBytes=0;
         chksum=0;
         NeedNewOffset=1;
         while ((BytesLeft) && (NeedNewOffset)) {     // Find first location to write next
            if ((aDesc==0) || (aDesc & aMemory->GetDescriptor(CurrAddr)) ||
                 ((FillMode!=DFC_FILL_TYPE(NO_FILL)) &&
                  (FillMode!=DFC_FILL_TYPE(CONDITIONAL_FILL_WITH)) &&
                  (FillMode!=DFC_FILL_TYPE(CONDITIONAL_FILL_WITH_RANDOM)))) {
               if (UsePhysicalAddr) {
                  RealAddr=aMemory->GetPhysicalAddr(CurrAddr)+NewBase;
               } else {
                  RealAddr=CurrAddr+NewBase;
               }
               OffsetAddr=(unsigned int)(RealAddr&0xFFFF);
               if (!LowestFound) {
                  LowestOffset=OffsetAddr;
                  LowestFound=1;
               }
               if (((RealAddr/65536UL)*0x1000UL)!=SBA) {
                  SBA=(unsigned int)((RealAddr/65536UL)*0x1000UL);
                  if (((RealAddr/65536UL)*0x1000UL)!=(unsigned long)(SBA))
							THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_OVERFLOW, 0, "");
                  TempByte=(256-(((SBA/256)+(SBA%256)+4)%256))%256;
                  sprintf(WriteBuff, ":02000002%04X%02X\r\n", SBA, TempByte);
                  aFile->write(WriteBuff, strlen(WriteBuff));
                  if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0 ,"");
                  LineCount++;
               }
               NeedNewOffset=0;
            } else {
               BytesLeft--;
               CurrAddr++;
            }
         }

		 for (i=0; ((i<32) && (!NeedNewOffset) && (BytesLeft)); ++i) {
            if ((aDesc==0) || (aDesc & aMemory->GetDescriptor(CurrAddr))) {
               TempByte=aMemory->GetByte(CurrAddr);
               NoFill=0;   // Fill, cause we have a byte
            } else {
               NoFill=0;   // Default to Fill
               switch GET_DFC_FILL_TYPE(FillMode) {
                  case DFC_FILL_TYPE(ALWAYS_FILL_WITH):
                           TempByte=GET_DFC_FILL_BYTE(FillMode);
                           break;
                  case DFC_FILL_TYPE(ALWAYS_FILL_WITH_RANDOM):
                           TempByte=(unsigned char)(rand()%256);
                           break;
                  default: TempByte=0x00;
                           NoFill=1;      // No-Fill
                           break;
               }
            }
            if (!NoFill) {    // If we have a byte, use it
               sprintf(TempStr, "%02X", TempByte);
               strcat(Buff, TempStr);
               chksum+=TempByte;
               NBytes++;
            }
            BytesLeft--;
            CurrAddr++;
            RealAddr++;
            if ((aDesc==0) || (aDesc & aMemory->GetDescriptor(CurrAddr)) ||
                 ((FillMode!=DFC_FILL_TYPE(NO_FILL)) &&
                  (FillMode!=DFC_FILL_TYPE(CONDITIONAL_FILL_WITH)) &&
                  (FillMode!=DFC_FILL_TYPE(CONDITIONAL_FILL_WITH_RANDOM)))) {
               if (UsePhysicalAddr) {
                  if (RealAddr!=(aMemory->GetPhysicalAddr(CurrAddr)+NewBase)) {
                     NeedNewOffset=1;
                  }
               }
               if (((RealAddr/65536UL)*0x1000UL)!=SBA) {
                  NeedNewOffset=1;
               } else {
                  if ((RealAddr&0xFFFF)==0) NeedNewOffset=1;
               }
            } else {
               NeedNewOffset=1;
            }
         }

         if (NBytes!=0) {
            chksum+=NBytes;
            chksum+=(OffsetAddr/256)+(OffsetAddr%256);
            chksum=(256-(chksum%256))%256;
            sprintf(WriteBuff, ":%02X%04X00%s%02X\r\n", NBytes, OffsetAddr, Buff, chksum);
            aFile->write(WriteBuff, strlen(WriteBuff));
            if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0 ,"");
            LineCount++;
         }
      }

      CurrRange=CurrRange->GetNext();
   }

   TempByte=(256-(((LowestOffset/256)+(LowestOffset%256)+1)%256))%256;
   sprintf(WriteBuff, ":00%04X01%02X\r\n", LowestOffset, TempByte);
   aFile->write(WriteBuff, strlen(WriteBuff));
   if (!aFile->good()) THROW_EXCEPTION_ERROR(EXCEPTION_ERROR::ERR_WRITEFAILED, 0 ,"");
   return(RetVal);
}

<file_sep>/programs/m6811dis/sfiledfc.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

/*
	SFileDFC -- Motorola S-File DataFileConverter Class

	This is the C++ Motorola S-File DataFileConverter Object Class Header File.
	It is a child of the DFC Object class.

	Author:	<NAME>
	Date:	February 10, 2000

	Written in: MS Visual C++ 5.0

*/

#ifndef SFILEDFC_H
#define SFILEDFC_H

#include <iostream>
#include "dfc.h"
#include "memclass.h"
#include "errmsgs.h"

class TDFC_SFile : virtual public CDFCObject {
public:
	virtual std::string GetLibraryName(void) const { return "motorola"; }
	virtual std::string GetShortDescription(void) const { return "Motorola Hex Data File Converter"; }
	virtual std::string GetDescription(void) const { return "Motorola Hex Data File Converter"; }

	const char *DefaultExtension(void) const { return "s19";	/* Could use "mot" */ }

	int RetrieveFileMapping(std::istream *aFile, unsigned long NewBase, TMemRange *aRange) const;

	int ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, unsigned char aDesc) const;

	int WriteDataFile(std::ostream *aFile, TMemRange *aRange, unsigned long NewBase, TMemObject *aMemory,
								unsigned char aDesc, int UsePhysicalAddr, unsigned int FillMode) const;

private:
	int _ReadDataFile(std::istream *aFile, unsigned long NewBase, TMemObject *aMemory, TMemRange *aRange, unsigned char aDesc) const;

};

#endif   // SFILEDFC_H

<file_sep>/programs/funcanal/FuncView/ChildFrm5.cpp
// ChildFrm5.cpp : implementation file
//
// Frame Window for the CompMatrix Views
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm5.cpp,v $
// Revision 1.1  2003/09/13 05:45:35  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"
#include "ChildFrm5.h"

#include "CompMatrixView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChildFrame5

IMPLEMENT_DYNCREATE(CChildFrame5, CChildFrameBase)

CChildFrame5::CChildFrame5()
{
}

CChildFrame5::~CChildFrame5()
{
}


BEGIN_MESSAGE_MAP(CChildFrame5, CChildFrameBase)
	//{{AFX_MSG_MAP(CChildFrame5)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildFrame5 message handlers

BOOL CChildFrame5::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	ASSERT(pContext != NULL);

	pContext->m_pNewViewClass = RUNTIME_CLASS(CCompMatrixView);
	if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) return FALSE;

	return TRUE;

//	return CChildFrameBase::OnCreateClient(lpcs, pContext);
}

<file_sep>/programs/m6811dis/gdc.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

//
//	Header for GDC -- Generic Disassembly Class
//

#ifndef _GDC_H_
#define _GDC_H_

#include "memclass.h"

#include <time.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>

// ============================================================================

class ifstreamControlFile : public std::ifstream
{
public:
	ifstreamControlFile(const std::string &strFilename)
		:	std::ifstream(),
			m_strFilename(strFilename)
	{
		open(strFilename.c_str(), std::ios_base::in);
	}

	std::string getFilename() const { return m_strFilename; }

private:
	std::string m_strFilename;
};

// ============================================================================

typedef std::vector<std::string> TStringArray;
typedef std::vector<unsigned char> TByteArray;
typedef std::vector<unsigned int> TWordArray;
typedef std::vector<unsigned int> TDWordArray;
typedef std::map<unsigned int, unsigned int> TAddressMap;
typedef std::map<unsigned int, TDWordArray> TAddressTableMap;
typedef std::map<unsigned int, TStringArray> TLabelTableMap;
typedef std::map<unsigned int, std::string> TAddressLabelMap;

// The following macro provides an easy method for GetFieldWidth to round field widths to the next tab-stop to prevent tab/space mixture
#define CALC_FIELD_WIDTH(n) (((m_nTabWidth != 0) && (m_bTabsFlag)) ? ((n/m_nTabWidth)+(((n%m_nTabWidth)!=0) ? 1 : 0))*m_nTabWidth : n)

// Forward declarations
class COpcodeEntry;
class COpcodeArray;
class COpcodeTable;
class CDisassembler;

// The following bit-mask definitions define the bits in the m_Control field
//	of each COpcodeEntry object that are processor independent and must be
//	properly used in each opcode defined by all overrides (GDC's).  This is
//	because these are used to control the overall disassembly operation.
//	All other bit-fields in m_Control can be defined and used as needed by
//	each override.  You will notice that the bit-fields in these definitions
//	start on the upper-bit of the upper-byte in the 32-bit m_Control DWord.
//	It is recommended that processor specific additions are made starting
//	at the other end -- that is the lower-bit of the lower-byte...  This
//	will allow the insertion of additional processor independent bits at the
//	top of the DWord in future updates and releases without necessarily
//	running into and conflicting with those defined by overrides.  It is
//	futher suggested that the entire upper-word be reserved for processor
//	independent functions and the entire lower-word be reserved for
//	dependent functions.  Also note that the usage need not be bit-by-bit
//	only, but can be numerical values occupying certain bit positions -- with
//	proper "and/or" masks and bit-shifting these can easily be converted to/from
//	bit-field equivalents.  (Names use OCTL_xxxx form)
#define OCTL_STOP	0x80000000ul		// Discontinue Disassembly - Upper-bit = 1


// Currently, all m_Group entries are used exclusively by processor
//	dependent functions.  But, it too should follow the guidelines above
//	so that in the future, if the group field is needed by the processor
//	independent functions, then they can be added in without changing
//	anything.  (Names use OGRP_xxxx form)


//	COpcodeEntry
//		This specifies exactly one opcode for the target processor.
class COpcodeEntry
{
public:
	COpcodeEntry();
	COpcodeEntry(int nNumBytes, unsigned char *Bytes, unsigned int nGroup, unsigned int nControl, const std::string & szMnemonic, unsigned int nUserData = 0);
	COpcodeEntry(const COpcodeEntry& aEntry);

	virtual void CopyFrom(const COpcodeEntry& aEntry);

	TWordArray		m_OpcodeBytes;	// Array of opcodes for this entry
	unsigned int	m_Group;		// Group declaration
	unsigned int	m_Control;		// Flow control
	unsigned int	m_UserData;		// User defined addition data storage
	std::string		m_Mnemonic;		// Printed mnemonic

	virtual COpcodeEntry &operator=(const COpcodeEntry& aEntry);
};


//	COpcodeArray
//		This specifies an array of opcodes that have the SAME initial
//		byte.  This class is exclusively a friend of COpcodeTable.
//		COpcodeTable controls the sorting and creating of these
//		arrays.  When new opcodes are added, COpcodeTable will properly
//		create and sort (via hash maps) these arrays...
class COpcodeArray : public std::vector<COpcodeEntry>
{
public:
	COpcodeArray();
	virtual ~COpcodeArray();

};


//	COpcodeTable
//		This function manages a single table of opcodes by properly
//		adding and maintaining opcode array's.  This class is a
//		mapping of initial opcode bytes to an array of COpcodeArray.
//		When adding a new opcode, this function first checks to
//		see if an array exists, if not it creates it - then it adds
//		the opcode to the array.   It also provides a "lookup"
//		function of "FindFirst" and "FindNext"...  These work sort
//		of like the traditional GetFirstPosition and GetNextAssoc
//		routines, but here they find the "First" and "Next" opcodes
//		that have a SPECIFIC byte.  The "First" function simply
//		returns the initial index position in the array +1 (0 = NOT Found)
//		The "Next" function updates the position and sets the
//		specified COpcodeEntry to the opcode entry value.  Note that
//		since arrays are used, the First/Next operation returns back
//		the opcodes for a common byte in the SAME order they were
//		added.  Currently, there is only an "Add" function and no remove!
//		It is also the users responsibility to not add duplicate or
//		conflicting opcodes!
class COpcodeTable : public std::map<unsigned char, COpcodeArray>
{
public:
	COpcodeTable();
	virtual ~COpcodeTable();

	virtual void AddOpcode(const COpcodeEntry& nOpcode);
};


//	CDisassembler
//		This class describes a generic disassembler class to handle disassembly.
//		It contains no processor dependent information, therefore this class
//		must be overriden to handle processor dependent operations.  It is also
//		setup to use the DFC converters and memory objects so that these
//		functions are not dependent on input file types.
//
//		In the override, the constructor and destructor must be
//		defined to setup opcodes and memory for the target processor!
//
//		The function "ReadControlFile" takes an already open CFile
//		object and reads in the control file.  The base function calls the
//		function 'ParseControlLine' for every line in the input file (comment
//		lines are automatically removed).  The override (if any) should
//		return TRUE if all is OK with the line being processed, otherwise,
//		it should set the m_ParseError with an error message and return FALSE.
//		The default message, if not set, for m_ParseError is "*** Error: Unknown error in line xxx".
//		The ReadControlFile routine will automatically output the control
//		file line number information for each m_ParseError message.
//		If default functionality is desired for the line, then the override
//		should call the CDisassembler::ParseControlLine function -- that way,
//		for the normally accepted options, the override doesn't have to worry
//		about processing them.  Plus, it gives the override a chance to create
//		new behavior for each command.
//
//		When branches are encountered, they are added to the m_BranchTable
//		map -- m_BranchTable is a map of arrays -- each array is a DWORD array that
//		contains every address that referenced the branch.  So, when a new branch is
//		found, the array is created -- when a branch is re-encountered, the address
//		that referenced the branch is added...  This is NEW to this disassembler from
//		the original! -- the original used only a simple table of branch addresses.
//
//		NOTE: Code references are added to the m_BranchTable arrays and data references
//		are added to the m_LabelRefTable arrays!!  This way, not only can we track
//		who referenced a particular address, but we can track how it was referenced.
//		All overrides should conform to this by making sure they add references to the
//		right place.  AddBranch function handles code references and AddLabel handles
//		data references.  When adding labels to code, add the reference using either
//		AddBranch and then call AddLabel without the refernece or just call
//		GenAddrLabel (which calls both AddBranch and AddLabel correctly).  When adding
//		data references, use either AddLabel or call GenDataLabel (GenDataLabel also
//		handles outputting of generated labels).
//		
class CDisassembler
{
public:
	// The following define the function identification flags:
	enum FUNC_FLAGS {	// Entries <128 = Stops:
						FUNCF_HARDSTOP = 0,			// Hard Stop = RTS or RTI encountered
						FUNCF_EXITBRANCH = 1,		// Exit Branch = Branch to a specified exit address
						FUNCF_BRANCHOUT = 2,		// Execution branched out (JMP, BRA, etc)
						FUNCF_SOFTSTOP = 3,			// Soft Stop = Code execution flowed into another function definition
						// Entries >=128 = Starts:
						FUNCF_ENTRY = 128,			// Entry Point Start
						FUNCF_INDIRECT = 129,		// Indirect Code Entry Point Start
						FUNCF_CALL = 130,			// Call Start Point (JSR, BSR, etc)
						FUNCF_BRANCHIN = 131 };		// Entry from a branch into (BEQ, BNE, etc)


	// The following define the memory descriptors for the disassembler memory.
	//		0 = The memory is unused/not-loaded
	//		10 = The memory is loaded, but hasn't been processed
	//		20 = The memory is loaded, has been processed, and found to be data, but not printable ASCII data
	//		21 = The memory is loaded, has been processed, and found to be printable ASCII data
	//		30 = The memory is loaded, has been processed, and is an indirect vector to Code
	//		31 = The memory is loaded, has been processed, and is an indirect vector to Data
	//		40 = The memory is loaded, has been processed, and found to be code
	//		41 = The memory is loaded, has been processed, and should be code, but was determined to be an illegal opcode
	//	NOTE: These should not be changed -- enough room has been allowed for future expansion!
	enum MEM_DESC {	DMEM_NOTLOADED = 0,
					DMEM_LOADED = 10,
					DMEM_DATA = 20,
					DMEM_PRINTDATA = 21,
					DMEM_CODEINDIRECT = 30,
					DMEM_DATAINDIRECT = 31,
					DMEM_CODE = 40,
					DMEM_ILLEGALCODE = 41 };

	// The following define field positions for obtaining field widths from overrides.
	//	Additional entries can be added on overrides, but this order should NOT change
	//	in order to maintain backward compatibility at all times:
	#define NUM_FIELD_CODES 6
	enum FIELD_CODE { FC_ADDRESS, FC_OPBYTES, FC_LABEL, FC_MNEMONIC, FC_OPERANDS, FC_COMMENT };

	// The following define mnemonic codes for use with the FormatMnemonic pure virtual
	//	function.  These are used to specify the retrieving of "special mnemonics" for
	//	things such as equates, data bytes, ascii text, etc.  Additional entries can be
	//	added on overrides, but this order should NOT change in order to maintain backward
	//	compatibility at all times:
	enum MNEMONIC_CODE { MC_OPCODE, MC_ILLOP, MC_EQUATE, MC_DATABYTE, MC_ASCII, MC_INDIRECT };

	// The following defines the label types when formating output.  The are flags that
	//	determine where the label is being referenced.  It is used by the FormatLabel
	//	function to determine what type of delimiter to add, if any.  This enum can be
	//	added to in overrides, but the existing entries should not be changed:
	enum LABEL_CODE { LC_EQUATE, LC_DATA, LC_CODE, LC_REF };

public:
	CDisassembler();
	virtual ~CDisassembler();

	virtual unsigned int GetVersionNumber(void);			// Base function returns GDC version is most-significant word.  Overrides should call this parent to get the GDC version and then set the least-significant word with the specific disassembler version.
	virtual std::string GetGDCLongName(void) = 0;		// Pure virtual.  Defines the long name for this disassembler
	virtual std::string GetGDCShortName(void) = 0;		// Pure virtual.  Defines the short name for this disassembler

	virtual bool ReadControlFile(ifstreamControlFile& inFile, bool bLastFile = true, std::ostream *msgFile = NULL, std::ostream *errFile = NULL, int nStartLineCount = 0);	// Read already open control file 'infile', outputs messages to 'msgFile' and errors to 'errFile', nStartLineCount = initial m_nCtrlLine value
	virtual bool ParseControlLine(const std::string & szLine, TStringArray& argv, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Parses a line from the control file -- szLine is full line, argv is array of whitespace delimited args.  Should return false ONLY if ReadControlFile should print the ParseError string to errFile with line info
	virtual bool ReadSourceFile(const std::string & szFilename, unsigned int nLoadAddress, const std::string & szDFCLibrary, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Reads source file named szFilename using DFC szDFCLibrary

	virtual bool ScanEntries(std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Scans through the entry list looking for code
	virtual bool ScanBranches(std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Scans through the branch lists looking for code
	virtual bool ScanData(const std::string & szExcludeChars, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);			// Scans through the data that remains and tags it as printable or non-printable
	virtual bool Disassemble(std::ostream *msgFile = NULL, std::ostream *errFile = NULL, std::ostream *outFile = NULL);		// Disassembles entire loaded memory and outputs info to outFile if non-NULL or opens and writes the file specified by m_sOutputFilename -- calls Pass1 and Pass2 to perform this processing

	virtual bool Pass1(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Performs Pass1 which finds code and data -- i.e. calls Scan functions
	virtual bool Pass2(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Performs Pass2 which is the actual disassemble stage
	virtual bool Pass3(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Performs Pass3 which creates the function output file

	virtual bool FindCode(std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Iterates through memory using m_PC finding and marking code.  It should add branches and labels as necessary and return when it hits an end-of-code or runs into other code found
	virtual bool ReadNextObj(bool bTagMemory, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Procedure to read next object code from memory.  The memory type is flagged as code (or illegal code).  Returns True if current code legal, else False.  OpMemory = object code from memory.  CurrentOpcode = Copy of COpcodeEntry for the opcode located.  PC is automatically advanced.
	virtual bool CompleteObjRead(bool bAddLabels = true, std::ostream *msgFile = NULL, std::ostream *errFile = NULL) = 0;	// Pure Virtual that finishes the opcode reading process as is dependent on processor.  It should increment m_PC and add bytes to m_OpMemory, but it should NOT flag memory descriptors!  If the result produces an invalid opcode, the routine should return FALSE.  The ReadNextObj func will tag the memory bytes based off of m_OpMemory!  If bAddLabels = FALSE, then labels and branches aren't added -- disassemble only!

	virtual bool RetrieveIndirect(std::ostream *msgFile = NULL, std::ostream *errFile = NULL) = 0;	// Pure Virtual. Retrieves the indirect address specified by m_PC and places it m_OpMemory for later formatting.  It is a pure virtual because of length and indian notation differences

	virtual std::string FormatMnemonic(MNEMONIC_CODE nMCCode) = 0;		// Pure Virtual.  This function should provide the specified mnemonic.  For normal opcodes, MC_OPCODE is used -- for which the override should return the mnemonic in the opcode table.  This is done to provide the assembler/processor dependent module opportunity to change/set the case of the mnemonic and to provide special opcodes.
	virtual std::string FormatOperands(MNEMONIC_CODE nMCCode) = 0;		// Pure Virtual.  This function should create the operands for the current opcode if MC_OPCODE is issued.  For others, it should format the data in m_OpMemory to the specified form!
	virtual std::string FormatComments(MNEMONIC_CODE nMCCode);			// This function should create any needed comments for the disassembly output for the current opcode or other special MC_OPCODE function.  This is where "undetermined branches" and "out of source branches" can get flagged by the specific disassembler.  The built in function calls FormatReferences and creates the references in the comments.  Overrides wishing to perform the same functionallity, should also call FormatReferences.

	virtual std::string FormatAddress(unsigned int nAddress);					// This function creates the address field of the disassembly output.  Default is "xxxx" hex value.  Override for other formats.
	virtual std::string FormatOpBytes(void);							// This function creates a opcode byte string from the bytes in m_OpMemory.  If another format is desired, override it
	virtual std::string FormatLabel(LABEL_CODE nLC, const std::string & szLabel, unsigned int nAddress);	// This function modifies the specified label to be in the Lxxxx format for the nAddress if szLabel is null. If szLabel is non-null no changes are made.  This function should be overridden to add the correct suffix delimiters as needed!
	virtual std::string FormatReferences(unsigned int nAddress);				// Makes a string to place in the comment field that contains all references for the specified address

	virtual int GetFieldWidth(FIELD_CODE nFC);			// Defines the widths of each output field.  Can be overridden to alter output formatting.  To eliminate space/tab mixing, these should typically be a multiple of the tab width
	virtual std::string MakeOutputLine(TStringArray& saOutputData);		// Formats the data in saOutputData, which should have indicies corresponding to FIELD_CODE enum, to a string that can be sent to the output file
	virtual void ClearOutputLine(TStringArray& saOutputData);

	virtual bool WriteHeader(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Writes the disassembly header comments to the output file.  Override in subclasses for non-default header

	virtual bool WritePreEquates(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed in the disassembly file prior to the equates section.  Default is do nothing.  Override as needed
	virtual bool WriteEquates(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Writes the equates table to the disassembly file.
	virtual bool WritePostEquates(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed in the disassembly file after the equates section.  Default is do nothing.  Override as needed

	virtual bool WritePreDisassembly(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed in the disassembly file prior to the main disassembly section.  Default writes several blank lines.  Override as needed
	virtual bool WriteDisassembly(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes the disassembly to the output file.  Default iterates through memory and calls correct functions.  Override as needed.
	virtual bool WritePostDisassembly(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed in the disassembly file after the main disassembly section, such as ".end".  Default is do nothing.  Override as needed

	virtual bool WritePreSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed in the disassembly file prior to a new section.  That is, a section that is loaded and analyzed.  A part of memory containing "not_loaded" areas would cause a new section to be generated.  This should be things like "org", etc.
	virtual bool WriteSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Writes the current section to the disassembly file.  Override as needed.
	virtual bool WritePostSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed in the disassembly file after a new section.  Default is do nothing, override as needed.

	virtual bool WritePreDataSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed prior to a data section -- that is a section that contains only DMEM_DATA directives.  This would be things like "DSEG", etc.  Default is do nothing. Override as needed.
	virtual bool WriteDataSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Writes a data section.
	virtual bool WritePostDataSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed after a data section.  Default is do nothing.  Typically this would be something like "ends"

	virtual bool WritePreCodeSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed prior to a code section -- such as "CSEG", etc.  Default is do nothing.  Override as needed.
	virtual bool WriteCodeSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Writes a code section.
	virtual bool WritePostCodeSection(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed after a code section.  Default is do nothing.  Typically this would be something like "ends"

	virtual bool WritePreFunction(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);		// Writes any info needed prior to a new function -- such as "proc".  The default simply writes a separator line "===".  Override as needed
	virtual bool WriteIntraFunctionSep(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes a function's intra code separation.  The default simply writes a separator line "---".  Override as needed
	virtual bool WritePostFunction(std::ostream& outFile, std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Writes any info needed after a function -- such as "endp".  The default simply writes a separator line "===".  Override as needed

	virtual bool ValidateLabelName(const std::string & aName);		// Parses a specified label to make sure it meets label rules

	virtual bool ResolveIndirect(unsigned int nAddress, unsigned int& nResAddress, int nType) = 0;	// Pure Virtual that Resolves the indirect address specified by nAddress of type nType where nType = 0 for Code locations and 1 for Data locations.  It returns the resolved address in nResAddress and T/F for mem load status

	virtual bool IsAddressLoaded(unsigned int nAddress, int nSize);	// Checks to see if the nSize bytes starting at address nAddress are loaded.  True only if all the bytes are loaded!

	virtual bool AddLabel(unsigned int nAddress, bool bAddRef = false, unsigned int nRefAddress = 0, const std::string & szLabel = std::string());		// Sets szLabel string as the label for nAddress.  If nAddress is already set with that string, returns FALSE else returns TRUE or all OK.  If address has a label and szLabel = NULL or zero length, nothing is added!  If szLabel is NULL or zero length, a null string is added to later get resolved to Lxxxx form.  If bAddRef, then nRefAddress is added to the reference list
	virtual bool AddBranch(unsigned int nAddress, bool bAddRef = false, unsigned int nRefAddress = 0);	// Adds nAddress to the branch table with nRefAddress as the referring address.  Returns T if all ok, F if branch address is outside of loaded space.  If nAddRef is false, a branch is added without a reference

	virtual void GenDataLabel(unsigned int nAddress, unsigned int nRefAddress, const std::string & szLabel = std::string(), std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Calls AddLabel to create a label for nAddress -- unlike calling direct, this function outputs the new label to msgFile if specified...
	virtual void GenAddrLabel(unsigned int nAddress, unsigned int nRefAddress, const std::string & szLabel = std::string(), std::ostream *msgFile = NULL, std::ostream *errFile = NULL);	// Calls AddLabel to create a label for nAddress, then calls AddBranch to add a branch address -- unlike calling direct, this function outputs the new label to msgFile if specified and displays "out of source" errors for the branches to errFile...
	virtual void OutputGenLabel(unsigned int nAddress, std::ostream *msgFile);		// Outputs a generated label to the msgFile -- called by GenAddrLabel and GenDataLabel
	virtual std::string GenLabel(unsigned int nAddress);		// Creates a default generated label.  Base form is Lxxxx, but can be overridden in derived classes for other formats

	virtual std::string GetExcludedPrintChars(void) = 0;	// Pure Virtual. Returns a list of characters excluded during datascan for printable scan
	virtual std::string GetHexDelim(void) = 0;				// Pure Virtual. Returns hexadecimal delimiter for specific assembler.  Typically "0x" or "$"
	virtual std::string GetCommentStartDelim(void) = 0;		// Pure Virtual. Returns start of comment delimiter string
	virtual std::string	GetCommentEndDelim(void) = 0;		// Pure Virtual. Returns end of comment delimiter string

	// Output Flags and Control Values:
	bool	m_bAddrFlag;		// CmdFileToggle, TRUE = Write addresses on disassembly
	bool	m_bOpcodeFlag;		// CmdFileToggle, TRUE = Write opcode listing as comment in disassembly file
	bool	m_bAsciiFlag;		// CmdFileToggle, TRUE = Convert printable data to ASCII strings
	bool	m_bSpitFlag;		// CmdFileToggle, Code-Seeking/Code-Dump Mode, TRUE = Code-Dump, FALSE = Code-Seek
	bool	m_bTabsFlag;		// CmdFileToggle, TRUE = Use tabs in output file.  Default is TRUE.
	bool	m_bAsciiBytesFlag;	// CmdFileToggle, TRUE = Outputs byte values of ASCII text as comment prior to ascii line (default)  FALSE = ASCII line only
	bool	m_bDataOpBytesFlag;	// CmdFileToggle, TRUE = Outputs byte values for data fields in OpBytes field for both printable and non-printable data, FALSE = no opbytes -- Default is FALSE

	int		m_nMaxNonPrint;		// CmdFile Value, Maximum number of non-printable characters per line
	int		m_nMaxPrint;		// CmdFile Value, Maximum number of printable characters per line
	int		m_nBase;			// CmdFile Value, Default number base for control file input
	int		m_nTabWidth;		// CmdFile Value, Width of tabs for output, default is 4

	std::string	m_sDefaultDFC;		// CmdFile Value, Default DFC Library -- used with single input file and on multi-file when not specified
	unsigned int	m_nLoadAddress;		// CmdFile Value, Load address for input file -- used only with single input file!
	std::string	m_sInputFilename;	// CmdFile Value, Filename for the input file -- used only with single input file!
	std::string	m_sOutputFilename;	// CmdFile Value, Filename for the disassembly output file
	std::string	m_sFunctionsFilename;	// CmdFile Value, Filename for the function output file
	TStringArray	m_sControlFileList;	// This list is appended with each control file read.  The only purpose for this list is for generating comments in the output file
	TStringArray	m_sInputFileList;	// This list is appended with each source file read (even with the single input name).  The only purpose for this list is for generating comments in the output file

	std::string m_sFunctionalOpcode;	// Functions File export opcode.  Cleared by ReadNextObj and set by CompleteObjRead.

	time_t	m_StartTime;		// Set to system time at instantiated

protected:
	int				m_nCtrlLine;	// Line Count while processing control file
	int				m_nFilesLoaded;	// Count of number of files successfully loaded by the control file
	COpcodeTable	m_Opcodes;		// Table of opcodes for this disassembler
	std::string		m_ParseError;	// Set during the control file parsing to indicate error messages

	TAddressMap	m_EntryTable;	// Table of Entry values (start addresses) from control file
	TAddressMap	m_FunctionsTable;	// Table of start-of and end-of functions
	TAddressMap	m_FuncExitAddresses;	// Table of address that are equivalent to function exit like RTS or RTI.  Any JMP or BRA or execution into one of these addresses will equate to a function exit
	TAddressTableMap m_BranchTable;	// Table mapping branch addresses encountered with the address that referenced it in disassembly.
	TLabelTableMap m_LabelTable;	// Table of labels both specified by the user and from disassembly.  Entry is pointer to array of labels.  A null entry equates back to Lxxxx.  First entry is default for "Get" function.
	TAddressTableMap m_LabelRefTable;	// Table of reference addresses for labels.  User specified labels have no reference added.
	TAddressLabelMap m_CodeIndirectTable;	// Table of indirect code vectors with labels specified by the user and from disassembly
	TAddressLabelMap m_DataIndirectTable;	// Table of indirect data vectors with labels specified by the user and from disassembly

	TMemObject		*m_Memory;		// Memory object for the processor.  Any overrides must define allocate/deallocate this appropriately
	unsigned int	m_PC;			// Program counter
	TByteArray		m_OpMemory;		// Array to hold the opcode currently being processed
	COpcodeEntry	m_CurrentOpcode;	// Copy of COpcodeEntry object of the opcode last located in the ReadNextObj function

	TMemRange		m_ROMMemMap;	// Mapping of ROM memory
	TMemRange		m_RAMMemMap;	// Mapping of RAM memory
	TMemRange		m_IOMemMap;		// Mapping of Memory Mapped I/O

private:
	typedef std::map<std::string, unsigned int> TParseCmdMap;
	TParseCmdMap	ParseCmds;		// Used internally to store control file commands
	TParseCmdMap	ParseCmdsOP1;	// Used internally to store control file commands
	TParseCmdMap	ParseCmdsOP2;	// Used internally to store control file commands
	TParseCmdMap	ParseCmdsOP3;	// Used internally to store control file commands
	TParseCmdMap	ParseCmdsOP4;	// Used internally to store control file commands
	TParseCmdMap	ParseCmdsOP5;	// Used internally to store control file commands

	int LAdrDplyCnt;
};

#endif	// _GDC_H_
<file_sep>/programs/funcanal/FuncView/SymbolMapListView.h
// SymbolMapListView.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: SymbolMapListView.h,v $
// Revision 1.1  2003/09/13 05:45:50  dewhisna
// Initial Revision
//
//

#if !defined(AFX_SYMBOLMAPLISTVIEW_H__FAB9EBAB_755D_4BD3_AFE9_966D0A3BF19B__INCLUDED_)
#define AFX_SYMBOLMAPLISTVIEW_H__FAB9EBAB_755D_4BD3_AFE9_966D0A3BF19B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CFuncViewPrjDoc;

/////////////////////////////////////////////////////////////////////////////
// CSymbolMapListView view

class CSymbolMapListView : public CListView
{
protected:
	CSymbolMapListView();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(CSymbolMapListView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CSymbolMapListView)
	public:
	virtual void OnInitialUpdate();
	protected:
	virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CSymbolMapListView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:
	void FillSymbolMapList(DWORD nSource = 0, LPCTSTR pszSymbolName = NULL);

	// Generated message map functions
protected:
	//{{AFX_MSG(CSymbolMapListView)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in SymbolMapListView.cpp
inline CFuncViewPrjDoc* CSymbolMapListView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_SYMBOLMAPLISTVIEW_H__FAB9EBAB_755D_4BD3_AFE9_966D0A3BF19B__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/ChildFrmBase.cpp
// ChildFrmBase.cpp : implementation of the CChildFrameBase class
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrmBase.cpp,v $
// Revision 1.1  2003/09/13 05:45:36  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "ChildFrmBase.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChildFrameBase

IMPLEMENT_DYNCREATE(CChildFrameBase, CMDIChildWnd)

BEGIN_MESSAGE_MAP(CChildFrameBase, CMDIChildWnd)
	//{{AFX_MSG_MAP(CChildFrameBase)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildFrameBase construction/destruction

CChildFrameBase::CChildFrameBase()
{
	m_strFrameTitle = "";
}

CChildFrameBase::~CChildFrameBase()
{

}

BOOL CChildFrameBase::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	m_strFrameTitle = cs.lpszName;

	return CMDIChildWnd::PreCreateWindow(cs);
}


/////////////////////////////////////////////////////////////////////////////
// CChildFrameBase diagnostics

#ifdef _DEBUG
void CChildFrameBase::AssertValid() const
{
	CMDIChildWnd::AssertValid();
}

void CChildFrameBase::Dump(CDumpContext& dc) const
{
	CMDIChildWnd::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CChildFrameBaes message handlers

void CChildFrameBase::OnUpdateFrameTitle(BOOL bAddToTitle)
{
	// update our parent window first
	GetMDIFrame()->OnUpdateFrameTitle(bAddToTitle);

	CDocument* pDocument = GetActiveDocument();
	if (bAddToTitle)
	{
		TCHAR szText[256+_MAX_PATH];
		if (pDocument == NULL) {
			lstrcpy(szText, m_strTitle);
		} else {
			lstrcpy(szText, pDocument->GetTitle());
			if (!m_strFrameTitle.IsEmpty()) lstrcat(szText, " - ");
			lstrcat(szText, m_strFrameTitle);
		}
		if (m_nWindow > 0)
			wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);

		// set title if changed, but don't remove completely
		SetWindowText(szText);
	}
}

<file_sep>/programs/m6811dis/stringhelp.h
//
//	Motorola 6811 Disassembler
//	Copyright(c)1996 - 2014 by <NAME>
//

#ifndef STRING_HELP_H
#define STRING_HELP_H

#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

// ============================================================================

// trim from start
static inline std::string &ltrim(std::string &s)
{
	s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
	return s;
}

// trim from end
static inline std::string &rtrim(std::string &s)
{
	s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
	return s;
}

// trim from both ends
static inline std::string &trim(std::string &s)
{
	return ltrim(rtrim(s));
}

static inline std::string &makeUpper(std::string &s)
{
	std::transform(s.begin(), s.end(), s.begin(), ::toupper);
	return s;
}

static inline int compareNoCase(const std::string &s1, const std::string &s2)
{
	std::string strUpper1 = s1;
	makeUpper(strUpper1);
	std::string strUpper2 = s2;
	makeUpper(strUpper2);
	return ((strUpper1 < strUpper2) ? -1 : ((strUpper1 > strUpper2) ? 1 : 0));
}

// ============================================================================

#endif		// STRING_HELP_H
<file_sep>/programs/funcanal/FuncView/OutputView.h
// OutputView.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: OutputView.h,v $
// Revision 1.1  2003/09/13 05:45:47  dewhisna
// Initial Revision
//
//

#if !defined(AFX_OUTPUTVIEW_H__F016EE3C_8F7F_4B35_A9C2_E54F1F80B97B__INCLUDED_)
#define AFX_OUTPUTVIEW_H__F016EE3C_8F7F_4B35_A9C2_E54F1F80B97B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CFuncViewPrjDoc;

/////////////////////////////////////////////////////////////////////////////
// COutputViewFile

class COutputView;

class COutputViewFile : public CFile
{
public:
// Constructors
	COutputViewFile(COutputView &rOutputView);
	virtual ~COutputViewFile();

#ifdef _DEBUG
public:
	virtual void Dump(CDumpContext& dc) const;
	virtual void AssertValid() const;
#endif

// Implementation:
protected:
	COutputView &m_rOutputView;
	BOOL m_bEraseOnNextWrite;

public:
	virtual DWORD GetPosition() const;
	BOOL GetStatus(CFileStatus& rStatus) const;
	virtual LONG Seek(LONG lOff, UINT nFrom);
	virtual void SetLength(DWORD dwNewLen);
	virtual UINT Read(void* lpBuf, UINT nCount);
	virtual void Write(const void* lpBuf, UINT nCount);
	virtual void Abort();
	virtual void Flush();
	virtual void Close();

	// Unsupported APIs
	virtual CFile* Duplicate() const;
	virtual void LockRange(DWORD dwPos, DWORD dwCount);
	virtual void UnlockRange(DWORD dwPos, DWORD dwCount);
};


/////////////////////////////////////////////////////////////////////////////
// COutputView view

class COutputView : public CEditView
{
protected:
	COutputView();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(COutputView)

// Attributes
public:
	CFuncViewPrjDoc* GetDocument();
	inline COutputViewFile *GetOutputFile() const { return m_pOutputViewFile; }

protected:
	COutputViewFile *m_pOutputViewFile;
	CFont m_fntOutput;

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(COutputView)
	public:
	virtual void OnInitialUpdate();
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~COutputView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

	// Generated message map functions
protected:
	//{{AFX_MSG(COutputView)
	afx_msg void OnDestroy();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in OutputView.cpp
inline CFuncViewPrjDoc* COutputView::GetDocument()
   { return (CFuncViewPrjDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_OUTPUTVIEW_H__F016EE3C_8F7F_4B35_A9C2_E54F1F80B97B__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/ChildFrm4.h
// ChildFrm4.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm4.h,v $
// Revision 1.1  2003/09/13 05:45:34  dewhisna
// Initial Revision
//
//

#if !defined(AFX_CHILDFRM4_H__852AB5AF_96B1_4F85_ABF2_00FE3BEB96DD__INCLUDED_)
#define AFX_CHILDFRM4_H__852AB5AF_96B1_4F85_ABF2_00FE3BEB96DD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ChildFrmBase.h"

class COutputView;

/////////////////////////////////////////////////////////////////////////////
// CChildFrame4 frame

class CChildFrame4 : public CChildFrameBase
{
	DECLARE_DYNCREATE(CChildFrame4)
protected:
	CChildFrame4();           // protected constructor used by dynamic creation

// Attributes
public:
	COutputView *m_pOutputView;

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CChildFrame4)
	protected:
	virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CChildFrame4();

	// Generated message map functions
	//{{AFX_MSG(CChildFrame4)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM4_H__852AB5AF_96B1_4F85_ABF2_00FE3BEB96DD__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/ChildFrm6.h
// ChildFrm6.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: ChildFrm6.h,v $
// Revision 1.1  2003/09/13 05:45:36  dewhisna
// Initial Revision
//
//

#if !defined(AFX_CHILDFRM6_H__92F9AA21_0C5F_4C43_BA72_95EF6BD85F4A__INCLUDED_)
#define AFX_CHILDFRM6_H__92F9AA21_0C5F_4C43_BA72_95EF6BD85F4A__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ChildFrmBase.h"

/////////////////////////////////////////////////////////////////////////////
// CChildFrame6 frame

class CChildFrame6 : public CChildFrameBase
{
	DECLARE_DYNCREATE(CChildFrame6)
protected:
	CChildFrame6();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CChildFrame6)
	protected:
	virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CChildFrame6();

	// Generated message map functions
	//{{AFX_MSG(CChildFrame6)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM6_H__92F9AA21_0C5F_4C43_BA72_95EF6BD85F4A__INCLUDED_)
<file_sep>/programs/funcanal/FuncView/FuncViewPrjVw.cpp
// FuncViewPrjVw.cpp : implementation of the CFuncViewPrjView class
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: FuncViewPrjVw.cpp,v $
// Revision 1.1  2003/09/13 05:45:45  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "FuncViewPrjDoc.h"
#include "FuncViewPrjVw.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjView

IMPLEMENT_DYNCREATE(CFuncViewPrjView, CTreeView)

BEGIN_MESSAGE_MAP(CFuncViewPrjView, CTreeView)
	//{{AFX_MSG_MAP(CFuncViewPrjView)
	ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateEditClear)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjView construction/destruction

CFuncViewPrjView::CFuncViewPrjView()
{
	m_hMatrixBaseNode = NULL;
}

CFuncViewPrjView::~CFuncViewPrjView()
{
}

BOOL CFuncViewPrjView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CTreeView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjView printing

BOOL CFuncViewPrjView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CFuncViewPrjView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CFuncViewPrjView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjView diagnostics

#ifdef _DEBUG
void CFuncViewPrjView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CFuncViewPrjView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CFuncViewPrjDoc* CFuncViewPrjView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CFuncViewPrjView message handlers

void CFuncViewPrjView::OnInitialUpdate()
{
	CTreeCtrl &theTree = GetTreeCtrl();

	theTree.ModifyStyle(0, TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT |
							TVS_SHOWSELALWAYS, SWP_NOACTIVATE);

	// Call default which will call OnUpdate which will call FillFileLists:
	CTreeView::OnInitialUpdate();
}

void CFuncViewPrjView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

	switch (lHint) {
		case 0:						// Normal Update
			FillFileLists();
			FillMatrixLists();
			break;

		case MATRIX_TYPE_BASE:		// Matrix list only update
			FillMatrixLists();
			break;
	}

	if ((lHint >= FILESET_TYPE_BASE) && (lHint <= FILESET_TYPE_LAST)) {
		// FILESET_TYPE_BASE+nFileSet = Document Fileset Function update (pHint = &CFuncViewFuncRef)
	}


	if ((lHint >= SYMBOL_MAP_TYPE_BASE) && (lHint <= SYMBOL_MAP_TYPE_LAST)) {
		// SYMBOL_MAP_TYPE_BASE+nSymbolMapType = Symbol Map update (pHint = &LPCTSTR)
	}
}

void CFuncViewPrjView::FillFileLists()
{
	CTreeCtrl &theTree = GetTreeCtrl();
	theTree.DeleteAllItems();

	m_hMatrixBaseNode = NULL;

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	HTREEITEM hBase = theTree.InsertItem(pDoc->GetPathName() /* GetTitle() */);
	if (hBase == NULL) return;
	theTree.SetItemData(hBase, 0);			// Root document title is 0

	int i, j;
	HTREEITEM hFileSet;
	HTREEITEM hFileEntry;

	for (i=0; i<pDoc->GetFileSetCount(); i++) {
		hFileSet = theTree.InsertItem(pDoc->GetFileSetDescription(i), hBase);
		if (hFileSet == NULL) continue;
		theTree.SetItemData(hFileSet, FILESET_TYPE_BASE + (i*2));	// FileSet bases are even-numbers above FILESET_TYPE_BASE

		for (j=0; j<pDoc->GetFileCount(i); j++) {
			hFileEntry = theTree.InsertItem(pDoc->GetFilePathName(i, j), hFileSet);
			if (hFileEntry == NULL) continue;
			theTree.SetItemData(hFileEntry, FILESET_TYPE_BASE + 1 + (i*2));	// FileSet Entries are odd-numbers above FILESET_TYPE_BASE
		}

		theTree.Expand(hFileSet, TVE_EXPAND);
	}

	theTree.Expand(hBase, TVE_EXPAND);
}

void CFuncViewPrjView::FillMatrixLists()
{
	CTreeCtrl &theTree = GetTreeCtrl();

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	if (m_hMatrixBaseNode == NULL) {
		m_hMatrixBaseNode = theTree.InsertItem("Matrix Input/Output File");
		if (m_hMatrixBaseNode == NULL) return;
	}

	// Delete all of the item's children:
	if (theTree.ItemHasChildren(m_hMatrixBaseNode)) {
		HTREEITEM hNextItem;
		HTREEITEM hChildItem = theTree.GetChildItem(m_hMatrixBaseNode);

		while (hChildItem != NULL) {
			hNextItem = theTree.GetNextItem(hChildItem, TVGN_NEXT);
			theTree.DeleteItem(hChildItem);
			hChildItem = hNextItem;
		}
	}

	CString strMatrixPathName = pDoc->GetMatrixPathName();

	if (!strMatrixPathName.IsEmpty()) {
		theTree.InsertItem(strMatrixPathName, m_hMatrixBaseNode);
	}

	theTree.Expand(m_hMatrixBaseNode, TVE_EXPAND);
}

void CFuncViewPrjView::OnEditClear() 
{
	CTreeCtrl &theTree = GetTreeCtrl();
	HTREEITEM hSel = theTree.GetSelectedItem();
	if (hSel == NULL) return;
	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	CString strName = theTree.GetItemText(hSel);
	DWORD nType = theTree.GetItemData(hSel);
	int ndx;

	if (nType < FILESET_TYPE_BASE) return;
	if ((nType % 2) != 1) return;

	ndx = pDoc->FindFile((nType - FILESET_TYPE_BASE - 1) / 2, strName);
	ASSERT(ndx != -1);			// Why did we not find it??
	if (ndx != -1) {
		if (pDoc->RemoveFile((nType - FILESET_TYPE_BASE - 1) / 2, ndx)) {
			theTree.DeleteItem(hSel);
			pDoc->SetModifiedFlag(TRUE);
			pDoc->UpdateAllViews(this);
		}
	}
}

void CFuncViewPrjView::OnUpdateEditClear(CCmdUI* pCmdUI) 
{
	CTreeCtrl &theTree = GetTreeCtrl();
	HTREEITEM hSel = theTree.GetSelectedItem();
	if (hSel == NULL) {
		pCmdUI->Enable(FALSE);
		return;
	}

	// Enable clearing for function description file filenames:
	DWORD nType = theTree.GetItemData(hSel);
	pCmdUI->Enable((nType >= FILESET_TYPE_BASE) && ((nType % 2) == 1));
}

<file_sep>/programs/funcanal/FuncView/CompMatrixView.cpp
// CompMatrixView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// $Log: CompMatrixView.cpp,v $
// Revision 1.1  2003/09/13 05:45:38  dewhisna
// Initial Revision
//
//

#include "stdafx.h"
#include "FuncView.h"

#include "CompMatrixView.h"
#include "FuncViewPrjDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCompMatrixView

IMPLEMENT_DYNCREATE(CCompMatrixView, CView)

CCompMatrixView::CCompMatrixView()
{
	m_pGridCtrl = NULL;
}

CCompMatrixView::~CCompMatrixView()
{
	if (m_pGridCtrl)
		delete m_pGridCtrl;
}


BEGIN_MESSAGE_MAP(CCompMatrixView, CView)
	//{{AFX_MSG_MAP(CCompMatrixView)
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	ON_COMMAND(ID_SYMBOLS_ADD, OnSymbolsAdd)
	ON_UPDATE_COMMAND_UI(ID_SYMBOLS_ADD, OnUpdateSymbolsAdd)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CCompMatrixView diagnostics

#ifdef _DEBUG
void CCompMatrixView::AssertValid() const
{
	CView::AssertValid();
}

void CCompMatrixView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CFuncViewPrjDoc* CCompMatrixView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFuncViewPrjDoc)));
	return (CFuncViewPrjDoc*)m_pDocument;
}
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
// CCompMatrixView printing

BOOL CCompMatrixView::OnPreparePrinting(CPrintInfo* pInfo) 
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CCompMatrixView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo) 
{
	if (m_pGridCtrl) m_pGridCtrl->OnBeginPrinting(pDC, pInfo);
}

void CCompMatrixView::OnPrint(CDC* pDC, CPrintInfo* pInfo) 
{
	if (m_pGridCtrl) m_pGridCtrl->OnPrint(pDC, pInfo);
}

void CCompMatrixView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo) 
{
	if (m_pGridCtrl) m_pGridCtrl->OnEndPrinting(pDC, pInfo);
}


/////////////////////////////////////////////////////////////////////////////
// CGridCtrl required handlers

void CCompMatrixView::OnDraw(CDC* pDC) 
{
	// Do nothing here -- CGridCtrl will draw itself for us
}

void CCompMatrixView::OnSize(UINT nType, int cx, int cy) 
{
	CView::OnSize(nType, cx, cy);

	if ((m_pGridCtrl) && (::IsWindow(m_pGridCtrl->m_hWnd))) {
		CRect rect;
		GetClientRect(rect);
		m_pGridCtrl->MoveWindow(rect);
	}
}

BOOL CCompMatrixView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    if ((m_pGridCtrl) && (::IsWindow(m_pGridCtrl->m_hWnd)))
        if (m_pGridCtrl->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
            return TRUE;

	return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

BOOL CCompMatrixView::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
//	return CView::OnEraseBkgnd(pDC);
}


/////////////////////////////////////////////////////////////////////////////
// CCompMatrixView message handlers

void CCompMatrixView::OnInitialUpdate() 
{
	if (m_pGridCtrl == NULL)
	{
		// Create the Gridctrl object
		m_pGridCtrl = new CGridCtrl;
		if (!m_pGridCtrl) return;

		// Create the Gridctrl window
		CRect rect;
		GetClientRect(rect);
		m_pGridCtrl->Create(rect, this, 100);

		// Set settings:
		m_pGridCtrl->SetEditable(FALSE);
		m_pGridCtrl->EnableDragAndDrop(FALSE);
	}

	// The following will call OnUpdate which will call FillMatrixHeaders
	//		and FillMatrixData
	CView::OnInitialUpdate();
}

void CCompMatrixView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if (pSender == this) return;

	switch (lHint) {
		case 0:						// Normal Update
		case MATRIX_TYPE_BASE:		// Matrix data changed
			FillMatrixHeaders();
			FillMatrixData();
			break;
	}
}

void CCompMatrixView::FillMatrixHeaders()
{
	if (m_pGridCtrl == NULL) return;

	CWaitCursor waitCursor;

	m_pGridCtrl->DeleteAllItems();

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	int nRows = pDoc->GetFuncCount(CFuncViewPrjDoc::FVFS_LEFT_FILES, -1);
	int nCols = pDoc->GetFuncCount(CFuncViewPrjDoc::FVFS_RIGHT_FILES, -1);

	try {
		m_pGridCtrl->SetRowCount(nRows+1);
		m_pGridCtrl->SetColumnCount(nCols+1);
		m_pGridCtrl->SetFixedRowCount(1);
		m_pGridCtrl->SetFixedColumnCount(1);
	}
	catch (CMemoryException& e)
	{
		e.ReportError();
		e.Delete();
		return;
	}

	// Set Column headers (right-hand function):
	CFuncDesc *pFunc;
	int nFileIndex;
	int nFuncIndex;
	int i;

	nFileIndex = 0;
	nFuncIndex = 0;
	for (i=0; i<nCols; i++) {
		pFunc = pDoc->GetNextFunction(CFuncViewPrjDoc::FVFS_RIGHT_FILES, nFileIndex, nFuncIndex);
		if (pFunc == NULL) continue;

		GV_ITEM anItem;
		anItem.mask = GVIF_TEXT|GVIF_FORMAT;
		anItem.row = 0;
		anItem.col = i+1;
		anItem.nFormat = DT_LEFT|DT_WORDBREAK|DT_NOPREFIX;
		anItem.strText = pFunc->GetMainName();
		m_pGridCtrl->SetItem(&anItem);
	}

	// Set Row headers (left-hand function):
	nFileIndex = 0;
	nFuncIndex = 0;
	for (i=0; i<nRows; i++) {
		pFunc = pDoc->GetNextFunction(CFuncViewPrjDoc::FVFS_LEFT_FILES, nFileIndex, nFuncIndex);
		if (pFunc == NULL) continue;

		GV_ITEM anItem;
		anItem.mask = GVIF_TEXT|GVIF_FORMAT;
		anItem.row = i+1;
		anItem.col = 0;
		anItem.nFormat = DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOPREFIX;
		anItem.strText = pFunc->GetMainName();
		m_pGridCtrl->SetItem(&anItem);
	}

	m_pGridCtrl->AutoSize(GVS_BOTH);
}

void CCompMatrixView::FillMatrixData(int nSingleRow, int nSingleCol)
{
	if (m_pGridCtrl == NULL) return;

	CWaitCursor waitCursor;

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	double **ppnMatrix = pDoc->GetMatrix();
	if ((!pDoc->HaveMatrix()) || (ppnMatrix == NULL)) return;

	int nRows = pDoc->GetMatrixRowCount();
	int nCols = pDoc->GetMatrixColumnCount();

	// Set Data:
	int i,j,k;
	double nMaxCompResultX;
	double nMaxCompResultY;
	CFuncDesc *pLeftFunc;
	int nLeftFileIndex;
	int nLeftFuncIndex;
	CString strLeftName;
	CFuncDesc *pRightFunc;
	int nRightFileIndex;
	int nRightFuncIndex;
	CString strRightName;
	CString strTemp;
	BOOL bLeft;

	if (nSingleRow != -1) {
		pDoc->GetFileFuncIndexFromLinearIndex(CFuncViewPrjDoc::FVFS_LEFT_FILES, nSingleRow,
													nLeftFileIndex, nLeftFuncIndex);
	} else {
		nLeftFileIndex = 0;
		nLeftFuncIndex = 0;
	}
	for (i=((nSingleRow != -1) ? nSingleRow : 0); i<((nSingleRow != -1) ? (nSingleRow+1) : nRows); i++) {
		nMaxCompResultX = 0;

		pLeftFunc = pDoc->GetNextFunction(CFuncViewPrjDoc::FVFS_LEFT_FILES, nLeftFileIndex, nLeftFuncIndex);
		if (pLeftFunc) {
			strLeftName = pLeftFunc->GetMainName();
		} else {
			strLeftName = "";
		}

		bLeft = pDoc->LookupLeftFuncAssociation(strLeftName, strTemp);

		if (nSingleCol != -1) {
			pDoc->GetFileFuncIndexFromLinearIndex(CFuncViewPrjDoc::FVFS_RIGHT_FILES, nSingleCol,
														nRightFileIndex, nRightFuncIndex);
		} else {
			nRightFileIndex = 0;
			nRightFuncIndex = 0;
		}
		for (j=0; j<nCols; j++) nMaxCompResultX = __max(nMaxCompResultX, ppnMatrix[i][j]);
		for (j=((nSingleCol != -1) ? nSingleCol : 0); j<((nSingleCol != -1) ? (nSingleCol+1) : nCols); j++) {
			pRightFunc = pDoc->GetNextFunction(CFuncViewPrjDoc::FVFS_RIGHT_FILES, nRightFileIndex, nRightFuncIndex);
			if (pRightFunc) {
				strRightName = pRightFunc->GetMainName();
			} else {
				strRightName = "";
			}

			GV_ITEM anItem;
			anItem.mask = ((ppnMatrix[i][j] != 0) ? GVIF_TEXT|GVIF_FORMAT|GVIF_BKCLR :
														GVIF_FORMAT|GVIF_BKCLR);
			anItem.row = i+1;
			anItem.col = j+1;
			anItem.nFormat = DT_RIGHT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOPREFIX;
			anItem.crBkClr = CLR_DEFAULT;
			if (ppnMatrix[i][j] != 0) anItem.strText.Format("%f%%", ppnMatrix[i][j]*100);
			if ((ppnMatrix[i][j] != 0) && (ppnMatrix[i][j] == nMaxCompResultX)) {
				nMaxCompResultY = 0;
				for (k=0; k<nRows; k++) nMaxCompResultY = __max(nMaxCompResultY, ppnMatrix[k][j]);
				if (nMaxCompResultX == nMaxCompResultY) {
					anItem.crBkClr = RGB(0, 192, 192);
				}
			}
			if (anItem.crBkClr == CLR_DEFAULT) {
				if (bLeft || pDoc->LookupRightFuncAssociation(strRightName, strTemp))
					anItem.crBkClr = RGB(255, 255, 0);
			}
			m_pGridCtrl->SetItem(&anItem);
		}
	}

	m_pGridCtrl->AutoSize(GVS_BOTH);
}

void CCompMatrixView::OnSymbolsAdd() 
{
	if (m_pGridCtrl == NULL) return;

	CWaitCursor waitCursor;

	CFuncViewPrjDoc *pDoc = GetDocument();
	if (pDoc == NULL) return;

	CCellID aCell(-1, -1);
	BOOL bDone = FALSE;
	CFuncDesc *pLeftFunc;
	CFuncDesc *pRightFunc;
	int nLeftFileIndex;
	int nLeftFuncIndex;
	CString strLeftName;
	int nRightFileIndex;
	int nRightFuncIndex;
	CString strRightName;
	double nCompResult;
	CSymbolMap &theSymbolMap = pDoc->GetSymbolMap();
	CString strTemp;
	int i;

	int nRows = pDoc->GetMatrixRowCount();
	int nCols = pDoc->GetMatrixColumnCount();

	while (1) {
		aCell = m_pGridCtrl->GetNextItem(aCell, GVNI_ALL | GVNI_SELECTED);
		if ((aCell.row == -1) || (aCell.col == -1)) break;
		pLeftFunc = pDoc->GetFileFuncIndexFromLinearIndex(CFuncViewPrjDoc::FVFS_LEFT_FILES, aCell.row-1, nLeftFileIndex, nLeftFuncIndex);
		pRightFunc = pDoc->GetFileFuncIndexFromLinearIndex(CFuncViewPrjDoc::FVFS_RIGHT_FILES, aCell.col-1, nRightFileIndex, nRightFuncIndex);
		if ((pLeftFunc == NULL) || (pRightFunc == NULL)) continue;

		strLeftName = pLeftFunc->GetMainName();
		strRightName = pRightFunc->GetMainName();

		if (pDoc->LookupLeftFuncAssociation(strLeftName, strTemp)) continue;
		if (pDoc->LookupRightFuncAssociation(strRightName, strTemp)) continue;

		if (!pDoc->GetCompDiffText().IsEmpty()) pDoc->GetCompDiffText() += "\n";
		pDoc->GetCompDiffText() += ::DiffFunctions(FCM_DYNPROG_GREEDY,
					pDoc->GetFuncDescFile(CFuncViewPrjDoc::FVFS_LEFT_FILES, nLeftFileIndex), nLeftFuncIndex,
					pDoc->GetFuncDescFile(CFuncViewPrjDoc::FVFS_RIGHT_FILES, nRightFileIndex), nRightFuncIndex,
					OO_ADD_ADDRESS, nCompResult, &theSymbolMap);

		pDoc->AddFunctionAssociation(strLeftName, strRightName);

		nLeftFileIndex = 0;
		nLeftFuncIndex = 0;
		for (i=0; i<nRows; i++) {
			pLeftFunc = pDoc->GetNextFunction(CFuncViewPrjDoc::FVFS_LEFT_FILES, nLeftFileIndex, nLeftFuncIndex);
			if (pLeftFunc == NULL) continue;
			if (pLeftFunc->GetMainName().Compare(strLeftName) == 0) FillMatrixData(i, -1);
		}

		nRightFileIndex = 0;
		nRightFuncIndex = 0;
		for (i=0; i<nCols; i++) {
			pRightFunc = pDoc->GetNextFunction(CFuncViewPrjDoc::FVFS_RIGHT_FILES, nRightFileIndex, nRightFuncIndex);
			if (pRightFunc == NULL) continue;
			if (pRightFunc->GetMainName().Compare(strRightName) == 0) FillMatrixData(-1, i);
		}
	}

	pDoc->UpdateAllViews(this, SYMBOL_MAP_ALL, NULL);
	pDoc->UpdateAllViews(this, COMP_DIFF_TYPE_BASE, NULL);	// Update CompDiffEditViews
}

void CCompMatrixView::OnUpdateSymbolsAdd(CCmdUI* pCmdUI) 
{
	if (m_pGridCtrl == NULL) {
		pCmdUI->Enable(FALSE);
		return;
	}

	pCmdUI->Enable(m_pGridCtrl->GetSelectedCount() != 0);
}

