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

/////////////////////////////////////////////////////////////////////////////
//
//  File name: SHLMACRO.CPP
//
//  Description: The implementation file for the class: CMacroFile.
//
//  Author: Annie Yi
//
//  Date: 04/02/96
//
//  Modification:
//      1. 04/02/96, Initial version of the class: CMacroFile.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// Include files.
#include "stdafx.h"
#include "resource.h"

#include "shlmacro.h"
#include "tsttemp.h"
//for build
//#include "cpust.h"
#include <ctype.h>
#include <direct.h>
#include <dos.h>
#include "symblsvr.h"
//#include "hosterrs.h"
#include "goapi.h"

/////////////////////////////////////////////////////////////////////////////
// Debug flags.
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// Type definitions.


/////////////////////////////////////////////////////////////////////////////
// Macro definitions.


/////////////////////////////////////////////////////////////////////////////
// Global variables.
BOOL isDefineMacro = FALSE;
BOOL isRunMacro = FALSE;              
int nMacroIndex = -1;
BOOL isRunMac[CMacroFile::maxFileNo];
CMacroFile* pMacro[CMacroFile::maxFileNo];
CMacroFile* pMacroTemp = 0;
DWORD dwWhilePos;
char* pszExp;

/////////////////////////////////////////////////////////////////////////////
// Static variables.


/////////////////////////////////////////////////////////////////////////////
// External variables.
extern char szAppPath[_MAX_PATH+1];
extern int nAsmFlag;

/////////////////////////////////////////////////////////////////////////////
// Global function prototypes.
void MacroCmd(int nArgc, char* pszArgv[]);
void DelMacroCmd(int nArgc, char* pszArgv[]); 
void ShowMacroCmd(int nArgc, char* pszArgv[]);
void ListMacroCmd(int nArgc, char* pszArgv[]);
void MendCmd(int nArgc, char* pszArgv[]);
void RunMacroCmd(int nArgc, char* pszArgv[]);              
void DefineMacro(char* pszBuf, int nLen);
void ReadOneMacro(char* pszBuf);
void FreeMacro(void);
BOOL IsMacroInnerCommand(char* pszMacroLine);

/////////////////////////////////////////////////////////////////////////////
// Local function prototypes.


/////////////////////////////////////////////////////////////////////////////
// External function prototypes.
void ShowLine(char* pszBuffer);

// Defined in UICOM.CPP
int TestKey(WORD wKey);

// Defined in TSTTEMP.CPP
BOOL TstQueryStock(char* pszResult);

//int CheckExpressionStatus(char* pszArgv, BOOL& isResult);

//Defined in syntax.cpp
void DisplayOutOfMemory(void);             

/////////////////////////////////////////////////////////////////////////////
// Executable codes.

/////////////////////////////////////////////////////////////////////////////
// Public functions.
/////////////////////////////////////////////////////////////////////////////
//
//  Name:   MacroCmd().
//
//  Description: The main control routine of Macro command.
//
//  Input:  nArgc - Number of input parameters.
//          pszArgv - Input parameters.
//
//  Output: None.
//
//  Return: None.
//
/////////////////////////////////////////////////////////////////////////////
void MacroCmd(int nArgc, char* pszArgv[])
{                        
    // Assertion of the input parameters.
    ASSERT( nArgc == 2 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }   

	if ( isDefineMacro == FALSE ) {
		isDefineMacro = TRUE;
	}
	else {
		ShowLine("Error: Syntax error.");
		return;
	}	
	
	pMacroTemp  = new CMacroFile;
	
	pMacroTemp->CreateMacro(pszArgv[1]);

}	// End of MacroCmd().                   

void MendCmd(int nArgc, char* pszArgv[])
{
    ASSERT( nArgc == 1 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }                       
    isDefineMacro = FALSE;
//	pMacro->CloseMacro();	    
	if (pMacroTemp) {
		delete pMacroTemp;		
		pMacroTemp = 0;
	}	
	
}	//End of MendCmd().                              

void DefineMacro(char* pszBuf, int nLen)
{
	char* pszTemp = new char[nLen+3];
	strncpy(pszTemp, pszBuf, nLen);
	pszTemp[nLen] = '\n';
	pszTemp[nLen+1] = '\0';
	pMacroTemp -> DefineMacro(pszTemp);
    delete []pszTemp;
}	//End of DefineMacro().
                                              
void DelMacroCmd(int nArgc, char* pszArgv[])
{
    ASSERT( nArgc == 2 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }                       

	pMacroTemp = new CMacroFile;
	
	pMacroTemp->DelMacro(pszArgv[1]);
	if (pMacroTemp) {
		delete pMacroTemp;		
		pMacroTemp = 0;
	}	
	    
}   //End of DelMacroCmd().
                                              
void ListMacroCmd(int nArgc, char* pszArgv[])
{
    ASSERT( nArgc == 1 || nArgc == 2);
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }                       

	if (nArgc == 1) {
		CString strPath, strFile ;
		char* strMacro = new char[10];
		strPath = ::szAppPath;
		strPath += "macro\\";
		mkdir(strPath);
	                      
		struct _find_t  cFile;
	    strFile = strPath + "*.*";     
	    if (0 == _dos_findfirst( strFile, _A_NORMAL, &cFile )) {
			strcpy(strMacro, cFile.name);		
			ShowLine(strMacro);		
		    while( _dos_findnext( &cFile ) == 0 ) {
				strcpy(strMacro, cFile.name);		
				ShowLine(strMacro);
		    }
		}                
		delete []strMacro;
		strMacro = 0;
	}	
	else {
		pMacroTemp = new CMacroFile;				
		pMacroTemp -> ShowMacro(pszArgv[1]);		
		delete pMacroTemp;		    
	}
}	//End of ListMacroCmd().                  

void ShowMacroCmd(int nArgc, char* pszArgv[])
{
    ASSERT( nArgc == 2 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }                       
	pMacroTemp = new CMacroFile;				
	pMacroTemp -> ShowMacro(pszArgv[1]);		
	if (pMacroTemp) {
		delete pMacroTemp;		    
		pMacroTemp = 0;
	}	
	
}	//End of ShowMacroCmd().

void RunMacroCmd(int nArgc, char* pszArgv[])
{
    ASSERT( nArgc >= 1 && nArgc <= 11 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }                       
    
    // Execute Macro command.
    nMacroIndex++;
    //isRunMac[nMacroIndex] = TRUE; 
    if ( nMacroIndex >= CMacroFile::maxFileNo ) {
        //AfxMessageBox("Too many macro files opened.");
        //ShowLine("Too many macro files opened.");
        char pchText[256];
//        ErrGetErrorText(ER_TOO_MANY_MACRO, pchText);
        ShowLine(pchText);
        //isRunMac[nMacroIndex] = FALSE;        
        nMacroIndex--;
        return;
    } 
    else
    	isRunMac[nMacroIndex] = TRUE; 
    	
    // Allocate the memory.
    pMacro[nMacroIndex] = new CMacroFile;
    if ( !pMacro[nMacroIndex] ) {
        //AfxMessageBox("Insufficient Memory !");
        DisplayOutOfMemory();
        ASSERT( FALSE );
        return;
    }
        
    // Set the global flag.
    if ( !isRunMacro ) {
        isRunMacro = TRUE;
    }
    
    // Invoke the Macro command.
    ASSERT( pMacro[nMacroIndex] );
    if ( !pMacro[nMacroIndex]->MacroAction(nArgc, pszArgv) ) {
        delete []pMacro[nMacroIndex];
        pMacro[nMacroIndex] = 0;
        isRunMac[nMacroIndex] = FALSE;
        nMacroIndex--;
        // Reset the global flag.
        if ( -1 == nMacroIndex ) {
            isRunMacro = FALSE;
        }
    }

}	//End of RunMacroCmd().
                                             
// Read one line from the Macro file.
void ReadOneMacro(char* pszBuf)
{
    // Assertion of the input parameters.
    ASSERT( pszBuf );
    ASSERT( nMacroIndex >= 0 && nMacroIndex < CMacroFile::maxFileNo );
    
    // Read one line into the receiving buffer.
    ASSERT( pMacro[nMacroIndex] );
    pMacro[nMacroIndex]->ReadOneLine(pszBuf);

    // Delete an Macro object when EOF.
    if ( pMacro[nMacroIndex]->m_isEOF ) {
        *pszBuf = 0;
        delete []pMacro[nMacroIndex];
        pMacro[nMacroIndex] = 0;
        isRunMac[nMacroIndex] = FALSE;
        nMacroIndex--; 
        nAsmFlag = 0;
        // Reset the global flag.
        if ( -1 == nMacroIndex ) {
            isRunMacro = FALSE;
        }
    }

}   // End of ReadOneMacro().
                                             

// Free an Macro object.
void FreeMacro(void)
{
    // Assertion of the input parameters.
    
    // Not run Macro.
    if ( -1 == nMacroIndex ) {
        return;
    }
        
    // Free the Macro objects.
    for ( int i = 0; i < CMacroFile::maxFileNo; i++ ) {
        // Delete an Macro object.
        if ( pMacro[i] ) {
            delete []pMacro[i];
            pMacro[i] = 0;
        }
    }
    
    // Reset the global flag.
    isRunMacro = FALSE;
    nMacroIndex = -1;

}   // End of FreeMacro().


// Detect is it an Macro inner command.
// TRUE: is an inner command; FALSE: not an inner command.
BOOL IsMacroInnerCommand(char* pszMacroLine)
{
    // Assertion of the input parameters.
    ASSERT( pszMacroLine );
    ASSERT( pMacro[nMacroIndex] );
    
    // Is the inner command.
    BOOL isRetValue = pMacro[nMacroIndex]->MacroFilter(pszMacroLine);
    
    // Stop if Inner error happened.
    if ( CFileBase::INNER_MACRO_ERROR == pMacro[nMacroIndex]->m_nErrorID ) {
        pMacro[nMacroIndex]->m_nErrorID = CFileBase::NO_ERROR;
        delete []pMacro[nMacroIndex];
        pMacro[nMacroIndex] = 0;  
        isRunMac[nMacroIndex] = FALSE;
        nMacroIndex--;
        // Reset the global flag.
        if ( -1 == nMacroIndex ) {
            isRunMacro = FALSE;
        }
    }
    
    // Return back.
    return ( isRetValue );

}   // End of IsMacroInnerCommand().

                                              
/////////////////////////////////////////////////////////////////////////////
// Implementation codes of class: CMacroFile.

// Construction.
CMacroFile::CMacroFile()
{
    // Initial for EOF.
    m_isEOF = FALSE;
    
    // Initial for ERROR.
    m_isStop = FALSE;
                   
    // Initial for token.                   
    for ( int i = 0; i < (maxChar+1)/2; i++ ) {
        m_pszArgv[i] = 0;
    }
                      
    // Initial for Loop.
    m_lLoopIndex = -1;
    for ( i = 0; i < maxLoop; i++ ) {
        m_lLoopCount[i] = -1;
    }
                      
    for ( i = 0; i < 10; i++ ) {
        m_pszMacroArgv[i] = 0;
    }

    // Initial for IF & IF_NOT.
    m_isMatchedIF = FALSE;
    
    // Initial for ELSE.
    m_isMatchedELSE = FALSE;
    m_isSkipELSE = FALSE;
    
    // Initial for BeginMark & EndMark.
    m_isMatchedBegin = FALSE;

}	//End of CMacroFile::CMacroFile().                               
                                                
// Destruction.                                                
CMacroFile::~CMacroFile()
{
    // Close the Macro file.
    if ( OPEN_ERROR != m_nErrorID ) {
        CloseFile();
    }                 
    
    for (int i = 0; i < 10; i++) {
    	if (m_pszMacroArgv[i]) {
    		delete []m_pszMacroArgv[i];
			m_pszMacroArgv[i] = 0;
		}	    		
    }                                                                                                   
                                                                     
}	//End of CMacroFile::~CMacroFile().                                                                                                    

void CMacroFile::CreateMacro(char* pszMacroName)
{
	char pszDrive[_MAX_DRIVE];
    char pszDir[_MAX_DIR];
    char pszFname[_MAX_FNAME];
    char pszExt[_MAX_EXT];

    _splitpath(pszMacroName, pszDrive, pszDir, pszFname, pszExt);
                           
    if ( '\0' == pszDrive[0]  && '\0' == pszDir[0] ) {                       
	    //no path, 
		CString strPath, strFile;
		strPath = ::szAppPath;
		strPath += "macro";
		mkdir(strPath);
		//if ( '\0' == pszExt[0] ) {
			//no extention
		//	strcat(pszMacroName,".mac"); 
		//}	
		strFile = strPath +'\\';
		strFile = strFile + CString(pszMacroName); 
		m_strFileName = strFile;
	}
	else {                          
		//full path                          
		char* pszPath = new char[strlen(pszMacroName)+2];
		int nLen;

		_makepath(pszPath, pszDrive, pszDir, NULL, NULL);
		nLen = strlen(pszPath);
		if (pszPath[nLen-1] == '\\' && nLen >3) {		
			pszPath[nLen-1] = 0;	
		}			 
		if ( 0 == _chdir(pszPath) ) {
			//if ( '\0' == pszExt[0] ) {
			//	strcat(pszMacroName, ".mac");
			//}
			m_strFileName = pszMacroName;           
			delete []pszPath;
			pszPath = 0;
		}
		else {               
			isDefineMacro = FALSE;
			m_nErrorID = OPEN_ERROR;
			DisplayErrorMessage();			
			delete []pszPath;
			pszPath = 0;
			return;
		}		
//		strcpy(m_strFileName, pszMacroName);		
	}
	
	m_nOpenFlag = CFile::modeCreate | CFile::modeWrite | CFile::typeText;	
    OpenFile();
}	// End of CMacroFile::CreateMacro(). 

void CMacroFile::CloseMacro()
{
	CloseFile();	                  
	
}       //End of CMacroFile::CloseMacro().
                                        
//Write Macro to file                                        
void CMacroFile::DefineMacro(char* pszBuf)
{
    
    m_pszLineBuf = pszBuf;
    WriteToFile();

}		//End of CMacroFile::DefineMacro().                               
                                     
void CMacroFile::DelMacro(char* pszMacroName)
{
	CString strPath, strFile, strOneFile;
	strPath = ::szAppPath;
	strPath += "macro\\";
	mkdir(strPath);
                      
	//Delete all macro
	if ( 0 == stricmp(pszMacroName,"ALL"))  {        
		struct _find_t  cFile;
	    strFile = strPath + "*.*";
	    if (0 == _dos_findfirst( strFile, _A_NORMAL, &cFile )) {
			strOneFile = strPath + cFile.name; 
			remove(strOneFile);	    
		    while( _dos_findnext( &cFile ) == 0 ) {
				strOneFile = strPath + cFile.name; 
				remove(strOneFile);	    	    
		    }
		}                   
		return;
	}
/*
	//Delete one macro
	else {
		CString strName(pszMacroName);
		//strName += ".mac";
		strFile = strPath + strName;      
		if ( -1 == remove(strFile)) {
			m_nErrorID = DELETE_MACRO_ERROR;
			DisplayErrorMessage();			
		}	                                       
	}                      
    
    m_nErrorID = OPEN_ERROR;                                    
*/
	char pszDrive[_MAX_DRIVE];
    char pszDir[_MAX_DIR];
    char pszFname[_MAX_FNAME];
    char pszExt[_MAX_EXT];

    _splitpath(pszMacroName, pszDrive, pszDir, pszFname, pszExt);
                           
    if ( '\0' == pszDrive[0]  && '\0' == pszDir[0] ) {                       
	    //no path,
		CString strName(pszMacroName);
		strFile = strPath + strName;      
		if ( -1 == remove(strFile)) {
			m_nErrorID = DELETE_MACRO_ERROR;
			DisplayErrorMessage();			
		}	     
	}
	else {                          
		//full path                 
		CString strFile(pszMacroName);         		
		if ( -1 == remove(strFile)) {
			m_nErrorID = DELETE_MACRO_ERROR;
			DisplayErrorMessage();			
		}	           		
	}
                                                                
	m_nErrorID = OPEN_ERROR;                                                                                                    

}	//End of CMacroFile::DelMacro().                                     
                                     

BOOL CMacroFile::ShowMacro(char* pszMacroName)
{          
	char pszDrive[_MAX_DRIVE];
    char pszDir[_MAX_DIR];
    char pszFname[_MAX_FNAME];
    char pszExt[_MAX_EXT];

    _splitpath(pszMacroName, pszDrive, pszDir, pszFname, pszExt);
                           
    if ( '\0' == pszDrive[0]  && '\0' == pszDir[0] ) {                       
	    //no path, 	
		CString strPath, strFile ;
		strPath = ::szAppPath;
		strPath += "macro\\";
		mkdir(strPath);
		
		strFile = strPath + pszMacroName;
		//if ( '\0' == pszExt[0] ) {
			//no extention
		//	strFile += ".mac";
	    //}
		m_strFileName = strFile;
    }
	else {                          
		//full path         
		//if ( '\0' == pszExt[0] ) {
		//	strcat(pszMacroName, ".mac");
		//}
		m_strFileName = pszMacroName;                   
	}	
	m_nOpenFlag = CFile::modeRead | CFile::typeText;	
    OpenFile();                   
	if ( m_nErrorID == OPEN_ERROR) {
		DisplayErrorMessage();		
		return (FALSE);
	}	
	char* pszOneLine = new char[260];                       
	memset(pszOneLine, 0, 260);

	while ( !m_isEOF ) {
    	ReadOneLine(pszOneLine);
    	if ( strlen(pszOneLine) != 0 )
    		ShowLine(pszOneLine);
    }	
		
    delete []pszOneLine;
    pszOneLine = 0;
    return (TRUE);
    
}	//End of CMacroFile::ShowMacro().

void CMacroFile::ReadOneLine(char* pszBuf)
{
    // Assertion of the input parameters.
    ASSERT( pszBuf );
    
    // Supply the buffer to store the contents.
    m_pszLineBuf = pszBuf;
    
    // Read one line from the Macro file.
    ReadFromFile();                    
    
	
	// Replace the %n with argument
	CString str(m_pszLineBuf), strLine;
	strLine.Empty();
	int nPos;
	nPos = str.Find('%');	
	while ( -1 != nPos ) {
		if ( 0 != isdigit(str[nPos+1])) {
			char ch = str[nPos+1];
			if ( 0 != nPos) { 
				if (m_pszMacroArgv[ch-'0']) {
					strLine += str.Left(nPos);			
					strLine += m_pszMacroArgv[ch-'0'];
				}	
				else {
					strLine += str.Left(nPos+2);
				}
					
				//strLine += str.Right(str.GetLength()-nPos-1);
			}
			else {
				if (m_pszMacroArgv[ch-'0']) {
					strLine = m_pszMacroArgv[ch-'0'];
				}	
				else {
					strLine = str.Left(2);
				}             				
				//strLine += str.Right(str.GetLength()-nPos-1);
			}	
		}      
		else {
			strLine = str.Left(nPos+1);					
		}	
		str = str.Right(str.GetLength()-nPos-2);
		nPos = str.Find('%');				
	}       
	
	if (!strLine.IsEmpty()) 
		strcpy(m_pszLineBuf,strLine);	              
		              
    if ( FILE_END == m_nErrorID) {
    	m_nErrorID = MACRO_FILE_END; 
    }	
    
    // Save as the condition content.
    strcpy(m_pszCondition, m_pszLineBuf);

    // More than 255 characters or EOF.
    if ( NO_ERROR != m_nErrorID ) {
        m_isEOF = TRUE;
        DisplayErrorMessage();
        m_nErrorID = NO_ERROR;
    }
    
}   // End of CMacroFile::ReadOneLine().    

BOOL CMacroFile::MacroAction(int nArgc, char* pszArgv[])
{
    // Assertion of the input parameters.
    ASSERT( nArgc >= 1 && nArgc <= 11 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }
    ASSERT( NO_ERROR == m_nErrorID );
    
    // Parse the parameters.  
	CString strPath, strFile;
	char pszDrive[_MAX_DRIVE];
    char pszDir[_MAX_DIR];
    char pszFname[_MAX_FNAME];
    char pszExt[_MAX_EXT];

	char* pszMacro = new char[strlen(pszArgv[0])+2];
	strcpy(pszMacro, pszArgv[0]+1);
	_splitpath(pszMacro, pszDrive, pszDir, pszFname, pszExt);
    switch ( nArgc ) {
        case 1:
		    if ( '\0' == pszDrive[0]  && '\0' == pszDir[0] ) {                       
			    //no path, 	
				strPath = ::szAppPath;
				strPath += "macro";
				mkdir(strPath);
				//if ( '\0' == pszExt[0] ) {
					//no extention
        		//	strcat(pszMacro, ".mac"); 
        		//}	
				strFile = strPath +'\\';       
				strFile = strFile + CString(pszMacro); 
				m_strFileName = strFile;
			}
			else {
				//full path    
				//if ( '\0' == pszExt[0] ) {
				//	strcat(pszMacro, ".mac");
				//}
				m_strFileName = pszMacro;                   
			}	
            m_nOpenFlag |= CFile::modeRead; 
            //m_nOpenFlag = CFile::modeRead | CFile::shareExclusive;
            OpenFile();
            break;
		case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
			//Copy macro argument to m_pszMacroArgv[]	
			for ( i = 0 ; i < (nArgc-1); i++) {
				m_pszMacroArgv[i] = new char[strlen(pszArgv[i+1])+2];
				strcpy(m_pszMacroArgv[i], pszArgv[i+1]);
			}
		    if ( '\0' == pszDrive[0]  && '\0' == pszDir[0] ) {                       
			    //no path, 	
				strPath = ::szAppPath;
				strPath += "macro";
				mkdir(strPath);
				//if ( '\0' == pszExt[0] ) {
					//no extention
        		//	strcat(pszMacro, ".mac"); 
        		//}	
				strFile = strPath +'\\';       
				strFile = strFile + CString(pszMacro); 
				m_strFileName = strFile;
			}
			else {
				//full path    
				//if ( '\0' == pszExt[0] ) {
				//	strcat(pszMacro, ".mac");
				//}
				m_strFileName = pszMacro;                   
			}	
            m_nOpenFlag |= CFile::modeRead;
            //m_nOpenFlag = m_nOpenFlag | CFile::modeRead | CFile::shareDenyRead;
            OpenFile();
            break;
			
			/*
			strPath = ::szAppPath;
			strPath += "macro";
			mkdir(strPath);
			strcat(pszArgv[0],".mac"); 
			strFile = strPath +'\\';       
			strcpy(pszMacro, pszArgv[0]+1);
			strFile = strFile + CString(pszMacro); 
			m_strFileName = strFile;
            m_nOpenFlag |= CFile::modeRead;
            OpenFile();
            break;
            */                         
        default:
            ASSERT( FALSE );
            break;
    }       
    delete []pszMacro;
    pszMacro = 0;
    
    // Display the error message.
    if ( NO_ERROR != m_nErrorID ) {
        DisplayErrorMessage();
        return (FALSE);
    }
    else {
        return (TRUE);
    }

}	//End of CMacroFile::MacroAction().


// Filter the Macro line.
BOOL CMacroFile::MacroFilter(char* pszMacroLine)
{
    // Assertion of the input parameters.
    ASSERT( pszMacroLine );
    
    // Is the inner command.
    CheckInnerCommand(pszMacroLine);
    
    // Return back.
    if ( NOT_MACRO_INNER == m_nErrorID ) {
        m_nErrorID = NO_ERROR;
        return (FALSE);
    }
    else if ( INNER_MACRO_ERROR_ESC == m_nErrorID ) {
        DisplayErrorMessage();
        m_nErrorID = INNER_MACRO_ERROR;
        return (TRUE);
    }
    else if ( m_nErrorID > INNER_MACRO_ERROR ) {
        DisplayErrorMessage();
        m_nErrorID = (!m_isStop) ? NO_ERROR : INNER_MACRO_ERROR;
        return (TRUE);
    }
    else {
        return (TRUE);
    }

}   // End of CMacroFile::MacroFilter().
                               
// Check the inner command syntax.
void CMacroFile::CheckInnerCommand(char* pszMacroLine)
{
    // Assertion of the input parameters.
    ASSERT( pszMacroLine );
    
    // Copy the Inner command.
    strcpy(m_pszOneLine, pszMacroLine);
    strcat(m_pszOneLine, " ");
    m_nArgc = 0;
    
    // Inner command parsing.
    if ( TRUE == CommandParse() && m_nArgc ) {
        CommandKernel();
    }

    // Release the allocated space.
    for ( int i = 0; i < (maxChar+1)/2; i++ ) {
        if ( m_pszArgv[i] ) {
            delete []m_pszArgv[i];
            m_pszArgv[i] = 0;
        }
    }
    
}   // End of CMacroFile::CheckInnerCommand().


// Parse the inner commands.
BOOL CMacroFile::CommandParse(void)
{
    // Assertion of the input parameters.
    ASSERT( m_pszOneLine );
    
    // Get the token of the commands.
    char pszToken[maxChar+1];
    int nTokenLen = 0;
    BOOL isToken = FALSE;
    int nLen = strlen(m_pszOneLine);
/*    
	int index = 0;
	while ( m_pszOneLine[index] ) {
		if ( !isspace(m_pszOneLine[index]) ) break;
		index++; 	
	}          

	if ('$' == m_pszOneLine[index] ) {
		if ( m_pszArgv[0] ) {
        	delete []m_pszArgv[0];
        }
		m_pszArgv[0] = new char[nLen];
		strcpy(m_pszArgv[0], m_pszOneLine+index);
		m_nArgc = 1;
		return (TRUE);           
	}	
*/	

    for ( int i = 0; i < nLen; i++ ) {
        // Normal case.
        if ( TOKEN_KEY == m_pszOneLine[i] ) {
            if ( TRUE == isToken ) {
                pszToken[nTokenLen] = 0;
                if ( m_pszArgv[0] ) {
                    delete []m_pszArgv[0];
                    m_pszArgv[0] = 0;
                }
                m_pszArgv[0] = new char[nTokenLen+2];
                if ( !m_pszArgv[0] ) {
                    //AfxMessageBox("Insufficient Memory !");
                    DisplayOutOfMemory();
                    ASSERT( FALSE );
                    return (FALSE);
                }
                else {
                    isToken = FALSE;
                    strcpy(m_pszArgv[0], pszToken);
                }                     
                int nPos = i;
                char* p = &m_pszOneLine[nPos];
                BOOL isSpace = TRUE;
                while ( *p ) {
                	if ( ' ' == m_pszOneLine[nPos])
                		nPos++;
                	else {            
                		isSpace = FALSE;	
                		break;	
                	}	
                	p++;	
                }
                if ( isSpace) {
                	m_nArgc = 1;
                	break;
                }
                else {	
	                if ( m_pszArgv[1] ) {
	                    delete []m_pszArgv[1];
	                    m_pszArgv[1] = 0;
	                }
	                m_pszArgv[1] = new char[nLen-i+2];
	                if ( !m_pszArgv[1] ) {
	                    //AfxMessageBox("Insufficient Memory !");
	                    DisplayOutOfMemory();
	                    ASSERT( FALSE );
	                    return (FALSE);
	                }
	                else {  
	                	char pchTemp[256];                 
	                	i = nPos;
	                	for (int j = 0; j <= nLen-i; j++) {
	                		pchTemp[j] = m_pszOneLine[nPos];
	                		nPos++;
	                	}       
	                	pchTemp[j] = '\0';
		               	CString str(pchTemp);
		               	str.TrimRight();
		               	strcpy(m_pszArgv[1],str);
	                } 
	                m_nArgc = 2; 
	                break; 
	            }   
            }
        }
        else {
            if ( FALSE == isToken ) {
                isToken = TRUE;
            }
            pszToken[nTokenLen++] = m_pszOneLine[i];
        }
    }
/*
    for ( int i = 0; i < nLen; i++ ) {
        // Normal case.
        if ( TOKEN_KEY == m_pszOneLine[i] ) {
            if ( TRUE == isToken ) {
                pszToken[nTokenLen] = 0;
                if ( m_pszArgv[m_nArgc] ) {
                    delete []m_pszArgv[m_nArgc];
                }
                m_pszArgv[m_nArgc] = new char[nTokenLen+1];
                if ( !m_pszArgv[m_nArgc] ) {
                    AfxMessageBox("Insufficient Memory !");
                    ASSERT( FALSE );
                    return (FALSE);
                }
                else {
                    isToken = FALSE;
                    strcpy(m_pszArgv[m_nArgc++], pszToken);
                    // DumpText(m_pszArgv[m_nArgc-1]);
                    nTokenLen = 0;
                }    
            }
        }
        else {
            if ( FALSE == isToken ) {
                isToken = TRUE;
            }
            pszToken[nTokenLen++] = m_pszOneLine[i];
        }
    }
*/    
    // Return back.
    return (TRUE);

}   // End of CMacroFile::CommandParse().


// Inner command kernel.
void CMacroFile::CommandKernel(void)
{
    // Assertion of the input parameters.
    ASSERT( 0 == m_nErrorID );
    ASSERT( m_pszArgv[0] );    
    
    // Check the label.
    if ( ':' == m_pszArgv[0][0] ) {
        if ( 1 != m_nArgc ) {
            m_nErrorID = INNER_ERROR_SYNTAX;
        }
        else if ( !IsLabel(m_pszArgv[0]+1) ) {
            m_nErrorID = INNER_ERROR_LABEL;
        }
        return;
    }
    
    // Check the inner command keyword.
    char* pszInnerCommand[] = {
        "IF",
        "IF_NOT",
        "ELSE",
        "{",
        "}",
        "WHILE",
        "REM",
        "BELL",
        "ERROR",
        "GOTO",
        "LOOP",
        "LOOPEND",
        "PAUSE",
        "WAIT"
    };
         
    m_nErrorID = NOT_MACRO_INNER;

/*    
    //Check the command like "$a=1"
    //not complete
    if ( '$' == m_pszArgv[0][0] ) {
		//Call gates routine      
		m_nErrorID = NO_ERROR;
		return;    
    }
*/
    
    for ( int i = minInner; i <= maxInner; i++ ) {
        if ( !stricmp(m_pszArgv[0], pszInnerCommand[i]) ) {
            m_nErrorID = NO_ERROR;
            m_nCommandID = i;
            break;
        }
    }
    
    // Process the inner command.
    if ( NO_ERROR == m_nErrorID ) {
        ExecuteInnerCommand();
    }

}   // End of CMacroFile::CommandKernel().


// Execute the inner command.
void CMacroFile::ExecuteInnerCommand(void)
{
    // Assertion of the input parameters.
    ASSERT( m_nCommandID >= minInner && m_nCommandID <= maxInner );

    // Parse the inner commands.
    switch ( m_nCommandID ) {
        case MACRO_IF:
            MacroIf();
            break;
        case MACRO_IFNOT:
            MacroIfnot();
            break;
        case MACRO_ELSE:
            MacroElse();
            break;
        case MACRO_BEGINMARK:
            MacroBeginMark();
            break;
        case MACRO_ENDMARK:
            MacroEndMark();
            break;
        case MACRO_WHILE:
            MacroWhile();
            break;          
        case MACRO_REM:
            MacroRem();
            break;
        case MACRO_BELL:
            MacroBell();
            break;
        case MACRO_ERROR:
            MacroError();
            break;    
        case MACRO_GOTO:
            MacroGoto();
            break;
        case MACRO_LOOP:
            MacroLoop();
            break;
        case MACRO_LOOPEND:
            MacroLoopend();
            break;
        case MACRO_PAUSE:
            MacroPause();
            break;
        case MACRO_WAIT:
        	MacroWait();
        	break;    
        default:
            //ASSERT( FALSE );
            break;
    }

}   // End of CMacroFile::ExecuteInnerCommand().

/////////////////////////////////////////////////////////////////////////////
// Macro inner commands processing.

// IF "condition" 
void CMacroFile::MacroIf(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    if ( 1 == m_nArgc ) {
        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
        return;
    }
    
	if ( '\"' != m_pszArgv[1][0] ) {
		//Call Gates routing
	
		BOOL isResult;
		int nRet;
		nRet = CheckExpressionStatus(m_pszArgv[1], isResult);
		if ( nRet == -1 ) {
			m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
	        return;
		}
		else { 
			if ( TRUE == isResult ) {
		        // Pass through the IF block.
		        DWORD dwFilePos = GetPosition();
		        PassBlockBranch();
		        Seek(dwFilePos, CFile::begin);
		        m_isSkipELSE = TRUE;
		    }
			else {			
		        // Goto the ELSE statement.
		        PassBlockBranch();
		        DWORD dwFilePos = GetPosition();
		        if ( SearchELSE() ) {
		            // Pass through the ELSE block.
		            DWORD dwFilePos = GetPosition();
		            m_pszLineBuf = m_pszOneLine;
		            ReadFromFile();
		            PassBlockBranch();
		            Seek(dwFilePos, CFile::begin);
		        }
		        else {
		            Seek(dwFilePos, CFile::begin);
		        }
		    }
		}	
		
	}
	else {	    
    /*
    if ( '\"' != m_pszArgv[1][0] ) {
        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
        return;
    } */
	    if ( '\"' != m_pszArgv[m_nArgc-1][strlen(m_pszArgv[m_nArgc-1])-1] ) {
	        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
	        return;
	    }                                  
	           
	    // Save the condition.
	    char pszTemp[maxChar+1];
	    strcpy(pszTemp, m_pszCondition);
	    char* p = strstr(pszTemp, m_pszArgv[m_nArgc-1]);
	    ASSERT( p );
	    *p = 0;
	    p = strstr(pszTemp, m_pszArgv[1]);
	    if ( p ) {
	        strcpy(m_pszCondition, p+1);
	        strcat(m_pszCondition, m_pszArgv[m_nArgc-1]);
	    }
	    else {
	        strcpy(m_pszCondition, m_pszArgv[m_nArgc-1]+1);
	    }
	    m_pszCondition[strlen(m_pszCondition)-1] = 0;
	    
	    // Judge the condition.
	    if ( JudgeCondition() ) {
	        // Pass through the IF block.
	        DWORD dwFilePos = GetPosition();
	        PassBlockBranch();
	        Seek(dwFilePos, CFile::begin);
	        m_isSkipELSE = TRUE;
	    }
	    else {
	        // Goto the ELSE statement.
	        PassBlockBranch();
	        DWORD dwFilePos = GetPosition();
	        if ( SearchELSE() ) {
	            // Pass through the ELSE block.
	            DWORD dwFilePos = GetPosition();
	            m_pszLineBuf = m_pszOneLine;
	            ReadFromFile();
	            PassBlockBranch();
	            Seek(dwFilePos, CFile::begin);
	        }
	        else {
	            Seek(dwFilePos, CFile::begin);
	        }
	    }
	}
}   // End of CMacroFile::MacroIf().


// IF_NOT "condition"
void CMacroFile::MacroIfnot(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    if ( 1 == m_nArgc ) {
        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
        return;
    }

	if ( '\"' != m_pszArgv[1][0] ) {
		//Call Gates routing
	
		BOOL isResult;
		int nRet;                   
		nRet = CheckExpressionStatus(m_pszArgv[1], isResult);
		if ( nRet == -1 ) {
			m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
	        return;
		}
		else { 
			if ( FALSE == isResult ) {
		        // Pass through the IF block.
		        DWORD dwFilePos = GetPosition();
		        PassBlockBranch();
		        Seek(dwFilePos, CFile::begin);
		        m_isSkipELSE = TRUE;
		    }
			else {			
		        // Goto the ELSE statement.
		        PassBlockBranch();
		        DWORD dwFilePos = GetPosition();
		        //PassBlockBranch();
		        if ( SearchELSE() ) {
		            // Pass through the ELSE block.
		            DWORD dwFilePos = GetPosition();
		            m_pszLineBuf = m_pszOneLine;
		            ReadFromFile();
		            PassBlockBranch();
		            Seek(dwFilePos, CFile::begin);
		        }
		        else {
		            Seek(dwFilePos, CFile::begin);
		        }
		    }
		}	
		
	}
	else {	    
	    if ( '\"' != m_pszArgv[m_nArgc-1][strlen(m_pszArgv[m_nArgc-1])-1] ) {
	        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
	        return;
	    }
	
	    // Save the condition.
	    char pszTemp[maxChar+1];
	    strcpy(pszTemp, m_pszCondition);
	    char* p = strstr(pszTemp, m_pszArgv[m_nArgc-1]);
	    ASSERT( p );
	    *p = 0;
	    p = strstr(pszTemp, m_pszArgv[1]);
	    if ( p ) {
	        strcpy(m_pszCondition, p+1);
	        strcat(m_pszCondition, m_pszArgv[m_nArgc-1]);
	    }
	    else {
	        strcpy(m_pszCondition, m_pszArgv[m_nArgc-1]+1);
	    }
	    m_pszCondition[strlen(m_pszCondition)-1] = 0;
	    
	    // Judge the condition.
	    if ( !JudgeCondition() ) {
	        // Pass through the IF block.
	        DWORD dwFilePos = GetPosition();
	        PassBlockBranch();
	        Seek(dwFilePos, CFile::begin);
	        m_isSkipELSE = TRUE;
	    }
	    else {
	        // Goto the ELSE statement.
	        PassBlockBranch();
	        DWORD dwFilePos = GetPosition();
	        if ( SearchELSE() ) {
	            // Pass through the ELSE block.
	            DWORD dwFilePos = GetPosition();
	            m_pszLineBuf = m_pszOneLine;
	            ReadFromFile();
	            PassBlockBranch();
	            Seek(dwFilePos, CFile::begin);
	        }
	        else {
	            Seek(dwFilePos, CFile::begin);
	        }
	    }
	}
}   // End of CMacroFile::MacroIfnot().

// ELSE
void CMacroFile::MacroElse(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    switch ( m_nArgc ) {
        case 1:
            if ( m_isMatchedELSE ) {
                m_nErrorID = INNER_MACRO_ERROR_IF;
            }
            else if ( m_isMatchedBegin ) {
                m_nErrorID = INNER_MACRO_ERROR_END;
            }
            else {
                m_isMatchedELSE = TRUE;
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroElse().


// Begin mark: {
void CMacroFile::MacroBeginMark(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
    
    // Check the inner command syntax.
    switch ( m_nArgc ) {
        case 1:
            // {
            if ( m_isMatchedBegin ) {
                m_nErrorID = INNER_MACRO_ERROR_BEGIN;
            }
            else {
                m_isMatchedBegin = TRUE;
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }
    
}   // End of CMacroFile::MacroBeginMark().


// End mark: }
void CMacroFile::MacroEndMark(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
    
    // Check the inner command syntax.
    switch ( m_nArgc ) {
        case 1:
            // }
            if ( !m_isMatchedBegin ) {
                m_nErrorID = INNER_MACRO_ERROR_BEGIN;
            }
            else {
                // Skip ELSE block when condition is TRUE.
                if ( m_isSkipELSE ) {
                    SkipELSE();
                    m_isSkipELSE = FALSE;
	                m_isMatchedBegin = FALSE;
	                m_isMatchedELSE = FALSE;
	                m_isMatchedIF = FALSE;   
                }
                if ( !m_isSkipWhile ) {            
					int nRet;
					BOOL isResult;
					nRet = CheckExpressionStatus(pszExp, isResult);                	
					if ( nRet == -1 ) {
						m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
				        return;
					}
					else { 
						if ( TRUE == isResult ) {
							Seek(dwWhilePos, CFile::begin);
						}
						else {
							m_isSkipWhile = TRUE;
							delete []pszExp;
						}		
					}
					m_isMatchedBegin = FALSE;												
                }
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }
    
}   // End of CMacroFile::MacroEndMark().
                 
//While              
void CMacroFile::MacroWhile(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    if ( 1 == m_nArgc ) {
        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
        return;
    }
    
	if ( '\"' != m_pszArgv[1][0] ) {
		//Call Gates routing
	
		BOOL isResult;
		int nRet;                          
		dwWhilePos = GetPosition(); 
		pszExp = new char[strlen(m_pszArgv[1])+2];
		strcpy(pszExp, m_pszArgv[1]);
		nRet = CheckExpressionStatus(pszExp, isResult);
		if ( nRet == -1 ) {
			m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
	        return;
		}
		else { 
			if ( TRUE == isResult ) {
		        DWORD dwFilePos = GetPosition();
		        PassBlockBranch();
		        Seek(dwFilePos, CFile::begin);
    	        m_isSkipWhile = FALSE;
		    }
			else {			
		        // Skip the While block.
		        PassBlockBranch();
		        m_isSkipWhile = TRUE;
		        delete []pszExp;
		        //DWORD dwFilePos = GetPosition();
	            //Seek(dwFilePos, CFile::begin);
		    }
		}	         
				
	}
	else {
        m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
        return;
    }

}	// End of CMacroFile::MacroWhile().
                 
// REM [str]
void CMacroFile::MacroRem(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
    
    // Check the inner command syntax.
    // Only display the inner command.
    
}   // End of CMacroFile::MacroRem().

// BELL [count]
void CMacroFile::MacroBell(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
    
    // Check the inner command syntax.
    switch ( m_nArgc ) {
        char* p;
        case 1:
            // BELL
            MessageBeep(-1);
            break;
        case 2:
            // BELL count
            p = m_pszArgv[1];
            while ( *p ) {
                if ( !isxdigit(*(p++)) ) {
                    m_nErrorID = INNER_MACRO_ERROR_COUNT;
                    break;
                }
            }
            StrToVar(m_pszArgv[1]);
            if ( m_ulVar < 1 || m_ulVar > 0xFF ) {
                m_nErrorID = INNER_MACRO_ERROR_COUNT;
                break;
            }
            for ( i = 1; i <= (int)m_ulVar; i++ ) {
                DelayOneSecond();
                MessageBeep(-1);
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroBell().


// ERROR {ABORT|CONTINUE}
void CMacroFile::MacroError(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
    
    // Check the inner command syntax.
    switch ( m_nArgc ) {
        case 2:
            if ( !stricmp(m_pszArgv[1], "ABORT") ) {
                // ERROR abort
                m_isStop = TRUE;
            }
            else if ( !stricmp(m_pszArgv[1], "CONTINUE") ) {
                // ERROR continue
                m_isStop = FALSE;
            }
            else {
                m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroError().


// GOTO label
void CMacroFile::MacroGoto(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
    
    // Check the inner command syntax.
    switch ( m_nArgc ) {
        case 2:
            // GOTO label
            if ( !IsLabel(m_pszArgv[1]) ) {
                m_nErrorID = INNER_MACRO_ERROR_LABEL;
                break;
            }
            // Search the special Label.
            strcpy(m_pszLabel, ":");
            strcat(m_pszLabel, m_pszArgv[1]);
            GotoLabel();
            m_isMatchedBegin = FALSE;
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroGoto().

// LOOP
void CMacroFile::MacroLoop(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    switch ( m_nArgc ) {
        case 1:
            // LOOP
            if ( maxLoop - 1 == m_lLoopIndex ) {
                m_nErrorID = INNER_MACRO_ERROR_LOOP;
            }
            else {
                m_lLoopIndex++;
                m_dwLoopPos[m_lLoopIndex] = GetPosition();
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroLoop().


// LOOPEND [count]
void CMacroFile::MacroLoopend(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    switch ( m_nArgc ) {
        char* p;
        case 1:
            // LOOPEND
            if ( -1 == m_lLoopIndex ) {
                m_nErrorID = INNER_MACRO_ERROR_LOOPEND;
                break;
            }
            else {
                if ( 0 == m_lLoopCount[m_lLoopIndex] ) {
                    m_lLoopCount[m_lLoopIndex]--;
                    m_lLoopIndex--;
                    break;
                }
                else if ( -1 == m_lLoopCount[m_lLoopIndex] ) {
                    m_lLoopCount[m_lLoopIndex] = 1;
                }
                Seek(m_dwLoopPos[m_lLoopIndex], CFile::begin);
                m_lLoopCount[m_lLoopIndex]--;
            }
            break;
        case 2:
            // Syntax check.
            p = m_pszArgv[1];
            while ( *p ) {
                if ( !isxdigit(*(p++)) ) {
                    m_nErrorID = INNER_MACRO_ERROR_COUNT;
                    break;
                }
            }
            StrToVar(m_pszArgv[1]);
            if ( m_ulVar < 1 || m_ulVar > 0xFF ) {
                m_nErrorID = INNER_MACRO_ERROR_COUNT;
                break;
            }
            // LOOPEND count
            if ( -1 == m_lLoopIndex ) {
                m_nErrorID = INNER_MACRO_ERROR_LOOPEND;
                break;
            }
            else {
                if ( 0 == m_lLoopCount[m_lLoopIndex] ) {
                    m_lLoopCount[m_lLoopIndex]--;
                    m_lLoopIndex--;
                    break;
                }
                else if ( -1 == m_lLoopCount[m_lLoopIndex] ) {
                    m_lLoopCount[m_lLoopIndex] = (long)m_ulVar;
                }
                Seek(m_dwLoopPos[m_lLoopIndex], CFile::begin);
                m_lLoopCount[m_lLoopIndex]--;
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroLoopend().

// PAUSE [count]
void CMacroFile::MacroPause(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc > 0 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }

    // Check the inner command syntax.
    switch ( m_nArgc ) {
        char* p;
        int nKey;
        case 1:
            // PAUSE
            //ShowLine("Press any key to continue...");
	        char pchText[256];
//	        ErrGetErrorText(ER_CONTINUE, pchText);
	        ShowLine(pchText);

            do {
                nKey = TestKey(VK_ESCAPE);
            } while ( 0 == nKey );
            if ( 1 == nKey ) {
                m_nErrorID = INNER_MACRO_ERROR_ESC;
            }
            break;
        case 2:
            // PAUSE count
            p = m_pszArgv[1];
            while ( *p ) {
                if ( !isxdigit(*(p++)) ) {
                    m_nErrorID = INNER_MACRO_ERROR_COUNT;
                    break;
                }
            }
            StrToVar(m_pszArgv[1]);
            if ( m_ulVar < 1 || m_ulVar > 0xFF ) {
                m_nErrorID = INNER_MACRO_ERROR_COUNT;
                break;
            }
            for ( i = 0; i < (int)m_ulVar; i++ ) {
                DelayOneSecond();
            }
            break;
        default:
            m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
            break;
    }

}   // End of CMacroFile::MacroPause().

// WAIT
void CMacroFile::MacroWait(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    ASSERT( m_nArgc == 1 );
    for ( int i = 0; i < m_nArgc; i++ ) {
        ASSERT( m_pszArgv[i] );
    }
	
	if ( 1 != m_nArgc ) {                          
		m_nErrorID = INNER_MACRO_ERROR_SYNTAX;
		return;          
	}
	
	WaitCmd();    
                                       
}   // End of CMacroFile::MacroWait().                                       

/////////////////////////////////////////////////////////////////////////////
// Macro sub-routine.

// Check the valid label.
BOOL CMacroFile::IsLabel(char* pszArgv) const
{
    // Assertion of the input parameters.
    ASSERT( pszArgv );
    
    // Is the C-style label.
    if ( !iscsymf(pszArgv[0]) ) {
        return (FALSE);
    }
    else if ( '_' == pszArgv[0] && strlen(pszArgv) < 2 ) {
        return (FALSE);
    }
    else {
        BOOL isUnderscore = FALSE;
        char* p = pszArgv;
        if ( '_' == *p ) {
            isUnderscore = TRUE;
        }
        while ( *p ) {
            if ( !iscsym(*p) ) {
                return (FALSE);
            }
            else if ( '_' != *(p++) ) {
                isUnderscore = FALSE;
            }
        }
        if ( isUnderscore ) {
            return (FALSE);
        }
        else {
            return (TRUE);
        }
    }

}   // End of CMacroFile::IsLabel().


// Goto the special label.
void CMacroFile::GotoLabel(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    
    // Save the current file position.
    DWORD dwFilePos = GetPosition();
    
    // Search the label from the file beginning.
    SeekToBegin();
    do {
        m_pszLineBuf = m_pszOneLine;
        DWORD dwTempPos = GetPosition();
        ReadFromFile();
        if ( FILE_END == m_nErrorID ) {
            m_nErrorID = INNER_MACRO_ERROR_GOTO;
            Seek(dwFilePos, CFile::begin);
            break;
        }
        else if ( LONG_LINE == m_nErrorID ) {
            m_nErrorID = NO_ERROR;
            continue;
        }    
        else {
            int nLen = strlen(m_pszOneLine);
            if ( nLen > 0 ) {
                if ( '\n' == *(m_pszOneLine+nLen-1) ) {
                    nLen -= 1;
                    *(m_pszOneLine+nLen) = 0;
                }
            }
            strcat(m_pszOneLine, " ");
            m_nArgc = 0;
            if ( CommandParse() ) {
                if ( 1 == m_nArgc && !strcmp(m_pszArgv[0], m_pszLabel) ) {
                    Seek(dwTempPos, CFile::begin);
                    break;
                }
                else {
                    continue;
                }
            }
            else {
                Seek(dwFilePos, CFile::begin);
                break;
            }
        }
    } while ( TRUE );

}   // End of CMacroFile::GotoLabel().

// Skip ELSE statement if ending IF block.
void CMacroFile::SkipELSE(void)
{
    // Assertion of the input parameters.
                    
    // Test the next line.
    m_pszLineBuf = m_pszOneLine;
    DWORD dwFilePos = GetPosition();
    ReadFromFile();
    if ( NO_ERROR != m_nErrorID ) {
        Seek(dwFilePos, CFile::begin);
        m_nErrorID = NO_ERROR;
        return;
    }
    else {
        int nLen = strlen(m_pszOneLine);
        if ( nLen > 0 ) {
            if ( '\n' == *(m_pszOneLine+nLen-1) ) {
                nLen -= 1;
                *(m_pszOneLine+nLen) = 0;
            }
        }
        strcat(m_pszOneLine, " ");
        m_nArgc = 0;
        if ( CommandParse() ) {
            if ( 1 != m_nArgc || stricmp(m_pszArgv[0], "ELSE") ) {
                Seek(dwFilePos, CFile::begin);
                return;
            }
        }
        else {
            Seek(dwFilePos, CFile::begin);
            return;
        }
    }

    // Skip the ELSE block.
    PassBlockBranch();

}   // End of CMacroFile::SkipELSE().

// Judge the condition.
BOOL CMacroFile::JudgeCondition(void)
{
    // Assertion of the input parameters.
    ASSERT( m_pszCondition );
    
    // Query from the stock.
    if ( TstQueryStock(m_pszCondition) ) {
        return (TRUE);
    }
    else {
        return (FALSE);
    }

}   // End of CMacroFile::JudgeCondition().
                    
// Search ELSE statement.
BOOL CMacroFile::SearchELSE(void)
{
    // Assertion of the input parameters.
    
    // Search the ELSE statement.
    do {
        m_pszLineBuf = m_pszOneLine;
        DWORD dwFilePos = GetPosition();
        ReadFromFile();
        if ( NO_ERROR != m_nErrorID ) {
            m_nErrorID = NO_ERROR;
            return (FALSE);
        }
        else {
            BOOL isMatchedEnd = FALSE;
            int nLen = strlen(m_pszOneLine);
            if ( nLen > 0 ) {
                if ( '\n' == *(m_pszOneLine+nLen-1) ) {
                    nLen -= 1;
                    *(m_pszOneLine+nLen) = 0;
                }
            }
            strcat(m_pszOneLine, " ");
            m_nArgc = 0;
            if ( CommandParse() ) {
                if ( 1 == m_nArgc && !stricmp(m_pszArgv[0], "ELSE") ) {
                    if ( isMatchedEnd ) {
                        Seek(dwFilePos, CFile::begin);
                        return (TRUE);
                    }
                    else {
                        return (FALSE);
                    }
                }
                else if ( 1 == m_nArgc && !strcmp(m_pszArgv[0], "}") ) {
                    isMatchedEnd = TRUE;
                    continue;
                }
                else if ( 0 == m_nArgc ) {
                    continue;
                }
                else {
                    isMatchedEnd = FALSE;
                    continue;
                }
            }
            else {
                return (FALSE);
            }
        }
    } while ( TRUE );

}   // End of CMacroFile::SearchELSE().
           
// Pass through the whole block.
void CMacroFile::PassBlockBranch(void)
{
    // Assertion of the input parameters.
    ASSERT( NO_ERROR == m_nErrorID );
    
    // Search the Begin-mark at the next line.
    m_pszLineBuf = m_pszOneLine;
    ReadFromFile();
    if ( NO_ERROR != m_nErrorID ) {
        m_nErrorID = INNER_MACRO_ERROR_BEGIN;
        return;
    }
    else {
        int nLen = strlen(m_pszOneLine);
        if ( nLen > 0 ) {
            if ( '\n' == *(m_pszOneLine+nLen-1) ) {
                nLen -= 1;
                *(m_pszOneLine+nLen) = 0;
            }
        }
        strcat(m_pszOneLine, " ");
        m_nArgc = 0;
        if ( CommandParse() ) {
            if ( 1 != m_nArgc || strcmp(m_pszArgv[0], "{") ) {
                m_nErrorID = INNER_MACRO_ERROR_BEGIN;
                return;
            }
        }
        else {
            m_nErrorID = INNER_MACRO_ERROR_BEGIN;
            return;
        }
    }
        
    // Search the End-mark.
    do {
        m_pszLineBuf = m_pszOneLine;
        ReadFromFile();
        if ( NO_ERROR != m_nErrorID ) {
            m_nErrorID = INNER_MACRO_ERROR_END;
            break;
        }
        else {
            int nLen = strlen(m_pszOneLine);
            if ( nLen > 0 ) {
                if ( '\n' == *(m_pszOneLine+nLen-1) ) {
                    nLen -= 1;
                    *(m_pszOneLine+nLen) = 0;
                }
            }
            strcat(m_pszOneLine, " ");
            m_nArgc = 0;
            if ( CommandParse() ) {
                if ( 1 == m_nArgc && !strcmp(m_pszArgv[0], "}") ) {
                    break;
                }
                else {
                    continue;
                }
            }
            else {
                break;
            }
        }
    } while ( TRUE );

}   // End of CMacroFile::PassBlockBranch().
                                  
                               
// Test ESC key or any other key.
int CMacroFile::TestKey(WORD wKey)
{   
    MSG msg;
    if ( PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE|PM_NOYIELD) ) {
        PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE|PM_NOYIELD);
        if ( msg.message == WM_KEYDOWN && msg.wParam == wKey ) {
            return 1;
        }
        else if ( msg.message == WM_KEYDOWN && msg.wParam != wKey ) {
            return -1;
        }
        else if ( msg.message == WM_SYSKEYDOWN ) {
        	return 2;
        }
    }
    return 0;
}

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


