/***************************************************************************
**
**    $Header$
**
**    $Log$
** 
****************************************************************************/

/****************************************************************************
**
**  Name:      Ad196adr.cpp
**
**  Description:  The sub class C196adr deprived from the CFormatAddress
**                This class is process the 196 base family address
**                196 base family address has 3 kinds of format: 
**                      
**				  1. prefix:address  ( SFR address )
**                    prefix is the space area. Those are :
**						s: SFR	( S:80-S:FF )          
**	
**                2. absolute address ( Normal address area )
**		              range is 0~FFFFFF
** 
**                The address has one format: Hex 
**                      Hex has the prefix before address that is 0x
**                      
**
**                Another : the address is a symbol. The symbol has the format
**                as following:
**                      #ModuleName#SymbolName etc.
**                The process must deal all the statment described as before.
**
**  Status: Initialization
**          1996/09/16        Annie Yi
**
**  Copyright (C) 1996 Microtek International.  All rights reserved.
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include "stdafx.h"                        
#include <ctype.h>
#include "address.h"                // Include main head file
//#include "cpusvr.h"
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/                        

char* BASED_CODE SpacePrefix[11] = {
             "",        // Undefine space             
             "P0",
             "P1",
             "P2",
             "P3",
             "X0",
             "X1",
             "X2",
             "X3",
             "",
             "I",
      };

                       /****************************
                        *                          *
                        *       GLOBAL VARS        *
                        *                          *
                        ****************************/

ADDR_SIZE  dwpMax;        // program  max address
ADDR_SIZE  dwpMin;        // program  min address
ADDR_SIZE  dwxMax;        // external max address
ADDR_SIZE  dwxMin;        // external min address
ADDR_SIZE  dwiMax;        // internal max address
ADDR_SIZE  dwiMin;        // internal min address

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/****************************************************************************
**  Name:   C196Address
**
**  Description: Constructor
**
**  Parameters:
**     input:  any possible
**
**     output: none
**
*****************************************************************************/

// From CString
//
C196Address::C196Address(const CString &str)
{
	Initialize();

    m_strOriginAdr = str;   // Only set the origin string
    m_nDefaultIsHex = 1;
    IsString = TRUE;        // Construct from string
}

// From char*
//
C196Address::C196Address(const LPSTR str)
{
    Initialize();
	   
    m_strOriginAdr = str;   // Only set the origin string
    m_nDefaultIsHex = 1;
    IsString = TRUE;        // Construct from string
}

// From CString
//
C196Address::C196Address(const CString &str, const UINT isHex)
{
    Initialize();

    m_strOriginAdr = str;   // Only set the origin string
    m_nDefaultIsHex = isHex;
    IsString = TRUE;        // Construct from string
}

// From char*
//
C196Address::C196Address(const LPSTR str, const UINT isHex)
{
    Initialize();
   
    m_strOriginAdr = str;   // Only set the origin string
    m_nDefaultIsHex = isHex;   
    IsString = TRUE;        // Construct from string

}

// Can not construct from only numberica, must construct form the ADDR struct
// From DWORD(no use)
//
C196Address::C196Address(ADDR_SIZE dw)
{
    Initialize();
    m_dwAddress = dw;

}

// From ADDR struct
//
C196Address::C196Address(ADDRESS adr)
{
    Initialize();
    m_dwAddress = adr.adrAddress;
    m_enumSpace = adr.adrSpace;
    m_strPrefix = SpacePrefix[m_enumSpace];
}

  
/****************************************************************************
**  Name:   Initialize
**
**  Description: Initialize the C196Address. Call this function before any
**               Implenmentation but after the SetAdrRange();
**
**  Parameters:
**     input: none
**
**     output: none
*****************************************************************************/

void C196Address :: Initialize()
{
    // Init base class 
    m_strOriginAdr.Empty(); // Original address string. No any change
                            // Get from construct or Set function
    m_dwAddress = 0;        // The data of address(converted form string,
                            // or get from constructor)
                            // After converted successful, the m_dwAddress
                            // is the address.                                               
                            
    m_strPrefix.Empty();    // Prefix front the address.    
                            // Such as in 196 base family the prefix of
                            // p:0x987 is "p"
                            // In 86 family, the prefix is the segment or
                            // descriptor
                            // etc;
    m_strAddress.Empty();      // After split the prefix,
                            // In 196 family, it is the absoluted address
                            // In 86 family, it is the offset
                            // etc;
      
    m_strAddressHex.Empty();   // The converted hex address
    m_strAddressDec.Empty();   // The converted dec address
   
    m_enumSpace    = SPACE_UNDEFINE;
    IsString       = FALSE;
    m_enumRetCode  = ADR_OK;
    m_nDefaultIsHex = 1;
}


/****************************************************************************
**  Name:   ConvertCheck
**
**  Description:  The virtual function deprived from parent class.
**                Call this function to convert the address between text 
**                string and numberic. Check the address.
**                This function call the main processor -- Process()
**
**  Parameters:
**     input:  none
**
**     output: none
*****************************************************************************/

BOOL C196Address :: ConvertCheck()
{
    char  *lpszTemp1;
    FORMATTYPE ft;
    BOOL  bProcessOk = FALSE;

    if (IsString) {            // Construct from string
    	// If the input text string is empty, return false
        if (m_strOriginAdr.IsEmpty()) {
        	m_enumRetCode = ADR_EMPTY;
        	return FALSE;
      	}         
      
      	lpszTemp1 = new char[m_strOriginAdr.GetLength()+2];
      	ASSERT(NULL != lpszTemp1);
     	if (NULL == lpszTemp1) {
        	AfxMessageBox("memory alloc error");
         	return FALSE;
      	}         
      	memset(lpszTemp1, 0, m_strOriginAdr.GetLength()+2);
      	strcpy(lpszTemp1, m_strOriginAdr.GetBuffer(m_strOriginAdr.GetLength()));
      
      	SkipHeadWS(lpszTemp1);     // Skip the leading white space
      	CutTailWS(lpszTemp1);      // Skip the tail white space

      	if (!SplitPrefix(lpszTemp1)) { // Split the prefix and the address text
        	delete []lpszTemp1;
         	m_enumRetCode = ADR_FORMATERROR;
         	return FALSE;
      	}
      	// Has already set m_enumSpace, m_strSpace, m_strAddress by SplitPrefix
      
      	delete []lpszTemp1;
      
      	ft = IsWhichFormat();
      
      	CFormatHexStr   fmtHex(m_strAddress);
	    CFormatDecStr   fmtDec(m_strAddress);
	    CFormatSymbol   fmtSymbol(m_strAddress);

      	switch (ft) {
        	case IS_HEX:  
            	bProcessOk = Process(&fmtHex);
               	if (!bProcessOk) {
                	m_enumRetCode = ADR_INVALIDCHAR;
                  	return FALSE;
               	}
               	else {                             
                  	m_strAddressHex = fmtHex.GetHexString();
                  	m_dwAddress     = fmtHex.GetAddress();
               	}
               	break;

         	case IS_DEC:
               	bProcessOk = Process(&fmtDec);
               	if (!bProcessOk) {
                	m_enumRetCode = ADR_INVALIDCHAR;
                  	return FALSE;
               	}
               	else {                		
                  	m_strAddressDec = fmtDec.GetDecString();
                  	m_dwAddress  = fmtDec.GetAddress();
               	}
               	break;

         	case IS_SYM:
               	fmtSymbol.m_uSymData = 0;             // Symbol 0
               	if (SPACE_UNDEFINE != m_enumSpace) {
                  	m_enumRetCode = ADR_FORMATERROR;
                  	return FALSE;   
               	}
               	bProcessOk = Process(&fmtSymbol);
               	if (!bProcessOk) {
                  	m_enumRetCode = ADR_NOSYMBOL;
                  	return FALSE;
               	}
               	else {
                  	m_dwAddress  = (DWORD)fmtSymbol.GetAddress();
                  	m_enumSpace = (ADDR_SPACE)fmtSymbol.GetSpace();
               	}
               	break;                       
/*         
         case  IS_SYM_DATA:
               fmtSymbol.m_uSymData = 1;             // Symbol Data 1
               if (SPACE_UNDEFINE != m_enumSpace) {
                    m_enumRetCode = ADR_FORMATERROR;
                    return FALSE;   
               }
               bProcessOk = Process(&fmtSymbol);
               if (!bProcessOk) {
                  m_enumRetCode = ADR_NOSYMBOL;
                  return FALSE;
               }
               else {
                  m_dwAddress  = (DWORD)fmtSymbol.GetAddress();
                  m_enumSpace = SPACE_UNDEFINE; //(ADDR_SPACE)fmtSymbol.GetSpace();
               }
               break;                       
*/               
         	case IS_UNKNOWN:
               	return FALSE;         
      	}
	}
   	else {               // Construct from others
      	CFormatNumber   fmtNumber(m_dwAddress);
      
      	bProcessOk = Process(&fmtNumber);
      	if (!bProcessOk) {
         	m_enumRetCode = ADR_INVALIDCHAR;
         	return FALSE;
      	}
      	else {                                        
         	m_strAddressHex = fmtNumber.GetHexString();
         	m_strAddressDec = fmtNumber.GetDecString();
      	}
   	}
	
    // Check the range
    // must be modified              
   	if (SPACE_UNDEFINE != m_enumSpace) {
      	switch(m_enumSpace) {
	    	case  SPACE_P0:
	        case  SPACE_P1:
	        case  SPACE_P2:
	        case  SPACE_P3:
               	if (m_dwAddress > dwpMax || m_dwAddress < dwpMin) {
                  	m_enumRetCode = ADR_OUTRANGE;
                  	return FALSE;
               	}
               	break;
         	case  SPACE_X0:
         	case  SPACE_X1:
         	case  SPACE_X2:
         	case  SPACE_X3:
               	if (m_dwAddress > dwxMax || m_dwAddress < dwxMin) {
                  	m_enumRetCode = ADR_OUTRANGE;
                  	return FALSE;
               	}
               	break;
         	case  SPACE_I:
               	if (m_dwAddress > dwiMax || m_dwAddress < dwiMin) {
                  	m_enumRetCode = ADR_OUTRANGE;
                  	return FALSE;
               	}
               	break;                                 
      	}          
    }     
				
   	m_enumRetCode = ADR_OK;
   
   	return TRUE;
}

/****************************************************************************
**  Name:   Process
**
**  Description: Process the format. Call the format Convert() processor
**
**  Parameters:
**     input:  CFormatType &format
**
**     output: BOOL  TRUE if convert successful
*****************************************************************************/

BOOL C196Address :: Process(CFormatType *format)
{
   	format->Convert();
   	return format->m_bIsOk;
   	// if m_IsOk is FALSE, the format may include invalid char
}

/****************************************************************************
**  Name: SplitPrefix
**
**  Description: Split the origin address text string. Set the m_strAddress
**               and m_strPrefix
**
**  Parameters:
**     input:    char *lpsz
**
**     output:   BOOL   the format is correct, return TRUE
*****************************************************************************/

BOOL C196Address :: SplitPrefix(const char* lpsz)
{                   
   	int   nCount = 0;
   	int   nstrLength = strlen(lpsz);
   	char  *lpszPrefix;
   	char  *lpszAddr;
      
   	do {
      	if (':' == lpsz[nCount]) {
         	lpszPrefix = new char[nCount+1];
         	if (NULL == lpszPrefix)  	return FALSE;
         	memset(lpszPrefix, 0, nCount+1);   
         	strncpy(lpszPrefix, lpsz, nCount);
         	lpszAddr = new char[nstrLength-nCount+1];
         	if (NULL == lpszAddr)       return FALSE;
         	memset(lpszAddr, 0, nstrLength-nCount+1);   
         	strcpy(lpszAddr, lpsz+nCount+1);
         
         	if (0 == strlen(lpszAddr)) {
            	delete []lpszPrefix;
            	delete []lpszAddr;
            	return FALSE;
         	}                         
         	else {  
            	m_strAddress = lpszAddr;
         		m_strPrefix  = lpszPrefix;            
         	}
         
         	// Process the case: "s   :   0x100"
        	// Area has tail space
         
         	if (strlen(lpszPrefix) > 2 /*|| strlen(lpszAddr) > 8*/) {
         		delete []lpszPrefix;
            	delete []lpszAddr;
            	return FALSE;            
         	}
                  
         	if (' ' == lpszPrefix[strlen(lpszPrefix)-1]) {
            	delete []lpszPrefix;
            	delete []lpszAddr;
            	return FALSE;            
         	}
         	// Address string has leading space           
         
         	if (' ' == lpszAddr[0]) {
            	delete []lpszPrefix;
            	delete []lpszAddr;
            	return FALSE;
         	}
                    
         	delete []lpszPrefix;
         	delete []lpszAddr;
      	}
      	nCount++;
   	}while ((nCount < nstrLength) && (':' != lpsz[nCount-1]));
   
	CString strAnnie = m_strPrefix;
	                    
   	if ( m_strPrefix.IsEmpty() ) {
		CString strTemp(lpsz);                     
		//strTemp.MakeUpper();   
		int nLen = strTemp.GetLength();
		if ( strTemp.Find("0X") == 0 || strTemp.Find("0x") == 0) {
			if ( m_nDefaultIsHex ) {
				/*
				if ( nLen > 8 ) {
					return FALSE;
				}*/    
				strTemp = strTemp.Right(nLen-2);
			}	   
		}
		m_strAddress = strTemp;	               
		m_enumSpace = SPACE_UNDEFINE;//GetSpace(m_strAddress);		         						                                                     
   	}
   	else {           
      	m_strPrefix.MakeUpper();
      	int nLen = m_strPrefix.GetLength();
		int nBankInfo = GetBankInfo();
		switch(nBankInfo) {
			case COMB1:
				if ( nLen == 2 ) {
					if ( m_strPrefix[0] == 'P' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_P0;
								break;
							default:
							    return FALSE;
						}
					}        
					else {
						return FALSE;
					}
				}
				else if ( nLen == 1 && m_strPrefix[0] == 'I' ) {					
					m_enumSpace = SPACE_I;	
				}	
                else {
                	return FALSE;
                }
                break;
			case COMB2:
				if ( nLen == 2 ) {
					if ( m_strPrefix[0] == 'P' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_P0;
								break;
							case '1':
								m_enumSpace = SPACE_P1;
								break;
							default:
							    return FALSE;
						}
					}        
					else {
						return FALSE;
					}
				}
				else if ( nLen == 1 && m_strPrefix[0] == 'I' ) {					
					m_enumSpace = SPACE_I;	
				}	
                else {
                	return FALSE;
                }
                break;
			case COMB4:
				if ( nLen == 2 ) {
					if ( m_strPrefix[0] == 'P' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_P0;
								break;
							case '1':
								m_enumSpace = SPACE_P1;
								break;
							case '2':
								m_enumSpace = SPACE_P2;
								break;
							case '3':
								m_enumSpace = SPACE_P3;
								break;
							default:
							    return FALSE;
						}
					}        
					else {
						return FALSE;
					}
				}
				else if ( nLen == 1 && m_strPrefix[0] == 'I' ) {					
					m_enumSpace = SPACE_I;	
				}	
                else {
                	return FALSE;
                }
                break;
			case SEPB1:
				if ( nLen == 2 ) {
					if ( m_strPrefix[0] == 'P' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_P0;
								break;
							default:
							    return FALSE;
						}
					}
					else if ( m_strPrefix[0] == 'X' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_X0;
								break;
							default:
							    return FALSE;
						}					
					}                
					else {
						return FALSE;	
					}				
				}
				else if ( nLen == 1 && m_strPrefix[0] == 'I' ) {
					m_enumSpace = SPACE_I;
				}				
				else {
					return FALSE;
				}
				break;			
			case SEPB2:
				if ( nLen == 2 ) {
					if ( m_strPrefix[0] == 'P' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_P0;
								break;
							case '1':
								m_enumSpace = SPACE_P1;
								break;
							default:
							    return FALSE;
						}
					}
					else if ( m_strPrefix[0] == 'X' ) {
						switch (m_strPrefix[1]) {
							case '0':
								m_enumSpace = SPACE_X0;
								break;
							case '1':
								m_enumSpace = SPACE_X1;
								break;
							default:
							    return FALSE;
						}					
					}                
					else {
						return FALSE;	
					}				
				}
				else if ( nLen == 1 && m_strPrefix[0] == 'I' ) {
					m_enumSpace = SPACE_I;
				}				
				else {
					return FALSE;
				}
				break;			                      		
		}
   	}

   	return TRUE;           
}
             
          
///////////////////////////////////////////
//Return value

CString C196Address :: GetHexAddr()
{
   	return   m_strAddressHex;
}

CString C196Address :: GetDecAddr()
{
   	return   m_strAddressDec;
}

ADDR_RETCODE C196Address :: GetRetCode()
{
   	return   m_enumRetCode;
}

ADDR_SPACE C196Address :: GetSpace()
{
   	return   m_enumSpace;
} 
               
ADDR_SIZE C196Address :: GetAddress()
{
   	return CFormatAddress::m_dwAddress;
}


//////////////////////////////(EOF)//////////////////////////////

