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

/////////////////////////////////////////////////////////////////////////////
//
//  File name: TSTINC.CPP
//
//  Description: The implementation file for the class: CIncludeFile.
//
//  Author: Annie Yi, Chen Jun
//
//  Date: 05/19/95
//
//  Modification:
//      1. 05/19/95, Initial version of the class: CIncludeFile.
//
/////////////////////////////////////////////////////////////////////////////


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

#include "tstinc.h"
#include "tsttemp.h"
#include <ctype.h>
//#include "hosterrs.h"
#include "symblsvr.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 isRunInclude = FALSE;
BOOL isRunInc[CIncludeFile::maxFileNo];
int nIncludeIndex = -1;

CIncludeFile* pInclude[CIncludeFile::maxFileNo];


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


/////////////////////////////////////////////////////////////////////////////
// External variables.
extern int nAsmFlag;

/////////////////////////////////////////////////////////////////////////////
// Global function prototypes.
void IncludeCmd(int nArgc, char* pszArgv[]);
void TstReadOneInc(char* pszBuf);
void TstFreeInclude(int nIndex);
BOOL TstIsInnerCommand(char* pszIncLine);
void DisplayOutOfMemory(void);

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


/////////////////////////////////////////////////////////////////////////////
// External function prototypes.

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

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

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

void ShowLine(char* pszBuffer);

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

/////////////////////////////////////////////////////////////////////////////
// Public functions.

/////////////////////////////////////////////////////////////////////////////
//
//  Name:   IncludeCmd().
//
//  Description: The main control routine of Include command.
//
//  Input:  nArgc - Number of input parameters.
//          pszArgv - Input parameters.
//
//  Output: None.
//
//  Return: None.
//
/////////////////////////////////////////////////////////////////////////////
void IncludeCmd(int nArgc, char* pszArgv[])
{
    // Assertion of the input parameters.
    ASSERT( nArgc >= 2 && nArgc <= 12 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }
    
    // Execute Include command.
    nIncludeIndex++;
	//isRunInc[nIncludeIndex] = TRUE;    
    if ( nIncludeIndex >= CIncludeFile::maxFileNo ) {
        //AfxMessageBox("Too many include files opened.");
    	ShowLine("Too many include files opened.");
        //char pchText[256];
        //ErrGetErrorText(ER_TOO_MANY_INC, pchText);
        //ShowLine(pchText);

    	//isRunInc[nIncludeIndex] = FALSE;
        nIncludeIndex--;                
        return;
    }                                  
    else
    	isRunInc[nIncludeIndex] = TRUE;    

    // Allocate the memory.
    pInclude[nIncludeIndex] = new CIncludeFile;
    if ( !pInclude[nIncludeIndex] ) {
        //AfxMessageBox("Insufficient Memory !");
        DisplayOutOfMemory();
        ASSERT( FALSE );
        return;
    }
        
    // Set the global flag.
    if ( !isRunInclude ) {
        isRunInclude = TRUE;
    }
    
    // Invoke the Include command.
    ASSERT( pInclude[nIncludeIndex] );
    if ( !pInclude[nIncludeIndex]->IncludeAction(nArgc, pszArgv) ) {
        delete []pInclude[nIncludeIndex];
        pInclude[nIncludeIndex] = 0;
        isRunInc[nIncludeIndex] = FALSE;
        nIncludeIndex--;                       
        // Reset the global flag.
        if ( -1 == nIncludeIndex ) {
            isRunInclude = FALSE;
        }
    }

}   // End of IncludeCmd().


// Read one line from the Include file.
void TstReadOneInc(char* pszBuf)
{
    // Assertion of the input parameters.
    ASSERT( pszBuf );
    ASSERT( nIncludeIndex >= 0 && nIncludeIndex < CIncludeFile::maxFileNo );
    
    // Read one line into the receiving buffer.
    ASSERT( pInclude[nIncludeIndex] );
    pInclude[nIncludeIndex]->ReadOneLine(pszBuf);

    // Delete an Include object when EOF.
    if ( pInclude[nIncludeIndex]->m_isEOF ) {
        *pszBuf = 0;
        delete []pInclude[nIncludeIndex];
        pInclude[nIncludeIndex] = 0;
    	isRunInc[nIncludeIndex] = FALSE;
        nIncludeIndex--;
        nAsmFlag = 0;
        // Reset the global flag.
        if ( -1 == nIncludeIndex ) {
            isRunInclude = FALSE;
        }
    }

}   // End of TstReadOneInc().


// Free an Include object.
void TstFreeInclude(void)
{
    // Assertion of the input parameters.
    
    // Not run Include.
    if ( -1 == nIncludeIndex ) {
        return;
    }
    if ( pInclude[nIncludeIndex] ) {
    	delete []pInclude[nIncludeIndex];
		pInclude[nIncludeIndex] = 0;
	}	    	
/*        
    // Free the Include objects.
    for ( int i = 0; i < CIncludeFile::maxFileNo; i++ ) {
        // Delete an Include object.
        if ( pInclude[i] ) {
            delete []pInclude[i];
            pInclude[i] = 0;
        }
    }
    
    // Reset the global flag.
    isRunInclude = FALSE;
    nIncludeIndex = -1;
*/
}   // End of TstFreeInclude().


// Detect is it an include inner command.
// TRUE: is an inner command; FALSE: not an inner command.
BOOL TstIsInnerCommand(char* pszIncLine)
{
    // Assertion of the input parameters.
    ASSERT( pszIncLine );
    ASSERT( pInclude[nIncludeIndex] );
    
    // Is the inner command.
    BOOL isRetValue = pInclude[nIncludeIndex]->IncludeFilter(pszIncLine);
    
    // Stop if Inner error happened.
    if ( CFileBase::INNER_ERROR == pInclude[nIncludeIndex]->m_nErrorID ) {
        pInclude[nIncludeIndex]->m_nErrorID = CFileBase::NO_ERROR;
        delete []pInclude[nIncludeIndex];
        pInclude[nIncludeIndex] = 0;
    	isRunInc[nIncludeIndex] = FALSE;
        nIncludeIndex--;
        // Reset the global flag.
        if ( -1 == nIncludeIndex ) {
            isRunInclude = FALSE;
        }
    }
    
    // Return back.
    return ( isRetValue );

}   // End of TstIsInnerCommand().



/////////////////////////////////////////////////////////////////////////////
// Implementation codes of class: CIncludeFile.

// Construction.
CIncludeFile::CIncludeFile()
{
    // 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;
    }
    
    // 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 CIncludeFile::CIncludeFile().


// Destruction.
CIncludeFile::~CIncludeFile()
{
    // Close the Include file.
    if ( OPEN_ERROR != m_nErrorID ) {
        CloseFile();
    }
    
}   // End of CIncludeFile::~CIncludeFile().


// INclude      filename 
//              [[ arg0][ argv1][ argv2][ argv3][ argv4][ argv5]
//              [ argv6][ argv7][ argv8][ argv9]]
BOOL CIncludeFile::IncludeAction(int nArgc, char* pszArgv[])
{
    // Assertion of the input parameters.
    ASSERT( nArgc >= 2 && nArgc <= 12 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }
    ASSERT( NO_ERROR == m_nErrorID );
    
    // Parse the parameters.
    switch ( nArgc ) {
        case 2:
            m_strFileName = pszArgv[1];
            m_nOpenFlag = CFile::modeRead;// | CFile::shareExclusive;
            OpenFile();
            break;
/*            
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
            m_strFileName = pszArgv[1];
            m_nOpenFlag |= CFile::modeRead;
            OpenFile();
            break;
*/            
        default:
            ASSERT( FALSE );
            break;
    }
    
    // Display the error message.
    if ( NO_ERROR != m_nErrorID ) {
        DisplayErrorMessage();
        return (FALSE);
    }
    else {
        return (TRUE);
    }
        
}   // End of CIncludeFile::IncludeAction().


// Read one line from the Include file.
void CIncludeFile::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 Include file.
    ReadFromFile();
    
    // Save as the condition content.
    strcpy(m_pszCondition, pszBuf);
    
    // More than 255 characters or EOF.
    if ( NO_ERROR != m_nErrorID ) {
        //m_isEOF = ( FILE_END == m_nErrorID ) ? TRUE : FALSE;
        m_isEOF = TRUE;
        DisplayErrorMessage();
        m_nErrorID = NO_ERROR;
    }
    
}   // End of CIncludeFile::ReadOneLine().


// Filter the Include line.
BOOL CIncludeFile::IncludeFilter(char* pszIncLine)
{
    // Assertion of the input parameters.
    ASSERT( pszIncLine );
    
    // Is the inner command.
    CheckInnerCommand(pszIncLine);
    
    // Return back.
    if ( NOT_INNER == m_nErrorID ) {
        m_nErrorID = NO_ERROR;
        return (FALSE);
    }
    else if ( INNER_ERROR_ESC == m_nErrorID ) {
        DisplayErrorMessage();
        m_nErrorID = INNER_ERROR;
        return (TRUE);
    }
    else if ( m_nErrorID > INNER_ERROR ) {
        DisplayErrorMessage();
        m_nErrorID = (!m_isStop) ? NO_ERROR : INNER_ERROR;
        return (TRUE);
    }
    else {
        return (TRUE);
    }

}   // End of CIncludeFile::IncludeFilter().


// Check the inner command syntax.
void CIncludeFile::CheckInnerCommand(char* pszIncLine)
{
    // Assertion of the input parameters.
    ASSERT( pszIncLine );
    
    // Copy the Inner command.
    strcpy(m_pszOneLine, pszIncLine);
    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 CIncludeFile::CheckInnerCommand().


// Parse the inner commands.
BOOL CIncludeFile::CommandParse(void)
{
    // Assertion of the input parameters.
    ASSERT( m_pszOneLine );
    CString strTemp(m_pszOneLine);
    strTemp.TrimLeft();
                                    
	char pchTemp[300];                              
    strcpy(pchTemp, strTemp);                    
    
    // Get the token of the commands.
    char pszToken[maxChar+1];
    int nTokenLen = 0;
    BOOL isToken = FALSE;
    //int nLen = strlen(m_pszOneLine); 
    int nLen = strlen(pchTemp);
    
    for ( int i = 0; i < nLen; i++ ) {
        // Normal case.
        //if ( TOKEN_KEY == m_pszOneLine[i] ) { 
        if ( TOKEN_KEY == pchTemp[i] ) {
            if ( TRUE == isToken ) {
                pszToken[nTokenLen] = 0;
                if ( m_pszArgv[0] ) {
                    delete []m_pszArgv[0];
                }
                m_pszArgv[0] = new char[nTokenLen+1];
                if ( !m_pszArgv[0] ) {
                    //AfxMessageBox("Insufficient Memory !");
                    DisplayOutOfMemory();
                    ASSERT( FALSE );
                    return (FALSE);
                }
                else {
                    isToken = FALSE;
                    strcpy(m_pszArgv[0], pszToken);
                    // DumpText(m_pszArgv[m_nArgc-1]);
                    
                    int nPos = nTokenLen;
                    BOOL isSpace = TRUE;
                    for (int j = 0; j < nLen-nTokenLen; j++) {
                    	//if (m_pszOneLine[nPos] != ' ') {     
                    	if (pchTemp[nPos] != ' ') {    
                    	    isSpace = FALSE;
                    		break;
                    	}	
                    	nPos++;
                    }
                    
                    if (!isSpace ) {
                    	m_nArgc = 2;
	                    if ( m_pszArgv[1] ) {
	                    	delete []m_pszArgv[1];
	                	}
	                    m_pszArgv[1] = new char[nLen];  

	                    for ( j = 0; j < nLen-nTokenLen; j++) {
	                    	//m_pszArgv[1][j] = m_pszOneLine[nPos];
	                    	m_pszArgv[1][j] = pchTemp[nPos];
	                    	nPos++;
	                    }                     
	                    m_pszArgv[1][j] = 0;
	                    nPos = strlen(m_pszArgv[1])-1;
	                    for (j = nPos; j > 0  ; j--) {
	                    	if (m_pszArgv[1][j] == ' ') {
	                    		m_pszArgv[1][j] = 0;
	                    	}                    
	                    	else break;	                    		
	                    }
	                }        
	                else {
	                	m_nArgc = 1;
	                }
                    break;
                    //nTokenLen = 0;
                    
                }    
            }
        }
        else {
            if ( FALSE == isToken ) {
                isToken = TRUE;
            }
            pszToken[nTokenLen++] = pchTemp[i];
        }
    }
    
    // Return back.
    return (TRUE);

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


// Inner command kernel.
void CIncludeFile::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[] = {
        "BELL",
        "ERROR",
        "GOTO",
        "IF",
        "IF_NOT",
        "ELSE",
        "{",
        "}",
        "LOOP",
        "LOOPEND",
        "PAUSE",
        "REM",   
        "WAIT"
    };
         
    m_nErrorID = NOT_INNER;
    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 CIncludeFile::CommandKernel().


// Execute the inner command.
void CIncludeFile::ExecuteInnerCommand(void)
{
    // Assertion of the input parameters.
    ASSERT( m_nCommandID >= minInner && m_nCommandID <= maxInner );
    
    // Parse the inner commands.
    switch ( m_nCommandID ) {
        case INC_BELL:
            IncludeBell();
            break;
        case INC_ERROR:
            IncludeError();
            break;
        case INC_GOTO:
            IncludeGoto();
            break;
        case INC_IF:
            IncludeIf();
            break;
        case INC_IFNOT:
            IncludeIfnot();
            break;
        case INC_ELSE:
            IncludeElse();
            break;
        case INC_BEGINMARK:
            IncludeBeginMark();
            break;
        case INC_ENDMARK:
            IncludeEndMark();
            break;
        case INC_LOOP:
            IncludeLoop();
            break;
        case INC_LOOPEND:
            IncludeLoopend();
            break;
        case INC_PAUSE:
            IncludePause();
            break;
        case INC_REM:
            IncludeRem();
            break;
        case INC_WAIT:
        	IncludeWait();
        	break;    
        default:
            ASSERT( FALSE );
            break;
    }
            
}   // End of CIncludeFile::ExecuteInnerCommand().



/////////////////////////////////////////////////////////////////////////////
// Include inner commands processing.

// BELL [count]
void CIncludeFile::IncludeBell(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_ERROR_COUNT;
                    break;
                }
            }
            StrToVar(m_pszArgv[1]);
            if ( m_ulVar < 1 || m_ulVar > 0xFF ) {
                m_nErrorID = INNER_ERROR_COUNT;
                break;
            }
            for ( i = 1; i <= (int)m_ulVar; i++ ) {
                DelayOneSecond();
                MessageBeep(-1);
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludeBell().


// ERROR {ABORT|CONTINUE}
void CIncludeFile::IncludeError(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_ERROR_SYNTAX;
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludeError().


// GOTO label
void CIncludeFile::IncludeGoto(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_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_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludeGoto().


// IF "condition"
void CIncludeFile::IncludeIf(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_ERROR_SYNTAX;
        return;
    }

    //Add by Annie 4/16/96
    if ( '\"' != m_pszArgv[1][0] ) {
		//Call Gates routing
	
		BOOL isResult;
		int nRet;
		nRet = CheckExpressionStatus(m_pszArgv[1], isResult);
		if ( nRet == -1 ) {
            m_nErrorID = INNER_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();

				// Added by Chen.
		        if ( NO_ERROR != m_nErrorID ) {
	                Seek(dwFilePos, CFile::begin);
		            return;
		        }

		        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_ERROR_SYNTAX;
        return;
    }
    */
        if ( '\"' != m_pszArgv[m_nArgc-1][strlen(m_pszArgv[m_nArgc-1])-1] ) {
            m_nErrorID = INNER_ERROR_SYNTAX;
            return;
        }

    /*
        if ( m_isMatchedIF ) {
            m_nErrorID = INNER_ERROR_IF;
            return;
        }
        else {
            m_isMatchedIF = TRUE;
        }
    */

        // 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();

			// Added by Chen.
	        if ( NO_ERROR != m_nErrorID ) {
                Seek(dwFilePos, CFile::begin);
	            return;
	        }

            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 CIncludeFile::IncludeIf().


// IF_NOT "condition"
void CIncludeFile::IncludeIfnot(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_ERROR_SYNTAX;
        return;
    }
    */
    //Add by Annie 4/16/96
	if ( '\"' != m_pszArgv[1][0] ) {
		//Call Gates routing
	
		BOOL isResult;
		int nRet;
        nRet = CheckExpressionStatus(m_pszArgv[1], isResult);
		if ( nRet == -1 ) {
            m_nErrorID = INNER_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();

				// Added by Chen.
		        if ( NO_ERROR != m_nErrorID ) {
	                Seek(dwFilePos, CFile::begin);
		            return;
		        }

		        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_ERROR_SYNTAX;
        return;
    } */
        if ( '\"' != m_pszArgv[m_nArgc-1][strlen(m_pszArgv[m_nArgc-1])-1] ) {
            m_nErrorID = INNER_ERROR_SYNTAX;
            return;
        }

/*
        if ( m_isMatchedIF ) {
            m_nErrorID = INNER_ERROR_IF;
            return;
        }
        else {
            m_isMatchedIF = TRUE;
        }
*/

        // 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();

			// Added by Chen.
	        if ( NO_ERROR != m_nErrorID ) {
                Seek(dwFilePos, CFile::begin);
	            return;
	        }

            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 CIncludeFile::IncludeIfnot().


// ELSE
void CIncludeFile::IncludeElse(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_isMatchedIF ) {
                m_nErrorID = INNER_ERROR_ELSE;
            }
*/
            if ( m_isMatchedELSE ) {
                m_nErrorID = INNER_ERROR_IF;
            }
            else if ( m_isMatchedBegin ) {
                m_nErrorID = INNER_ERROR_END;
            }
            else {
                m_isMatchedELSE = TRUE;
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludeElse().


// Begin mark: {
void CIncludeFile::IncludeBeginMark(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_ERROR_BEGIN;
            }
            else {
                m_isMatchedBegin = TRUE;
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }
    
}   // End of CIncludeFile::IncludeBeginMark().


// End mark: }
void CIncludeFile::IncludeEndMark(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_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;
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }
    
}   // End of CIncludeFile::IncludeEndMark().


// LOOP
void CIncludeFile::IncludeLoop(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_ERROR_LOOP;
            }
            else {
                m_lLoopIndex++;
                m_dwLoopPos[m_lLoopIndex] = GetPosition();
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludeLoop().


// LOOPEND [count]
void CIncludeFile::IncludeLoopend(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_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_ERROR_COUNT;
                    break;
                }
            }
            StrToVar(m_pszArgv[1]);
            if ( m_ulVar < 1 || m_ulVar > 0xFF ) {
                m_nErrorID = INNER_ERROR_COUNT;
                break;
            }
            // LOOPEND count
            if ( -1 == m_lLoopIndex ) {
                m_nErrorID = INNER_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_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludeLoopend().


// PAUSE [count]
void CIncludeFile::IncludePause(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_ERROR_ESC;
            }
            break;
        case 2:
            // PAUSE count
            p = m_pszArgv[1];
            while ( *p ) {
                if ( !isxdigit(*(p++)) ) {
                    m_nErrorID = INNER_ERROR_COUNT;
                    break;
                }
            }
            StrToVar(m_pszArgv[1]);
            if ( m_ulVar < 1 || m_ulVar > 0xFF ) {
                m_nErrorID = INNER_ERROR_COUNT;
                break;
            }
            for ( i = 0; i < (int)m_ulVar; i++ ) {
                DelayOneSecond();
            }
            break;
        default:
            m_nErrorID = INNER_ERROR_SYNTAX;
            break;
    }

}   // End of CIncludeFile::IncludePause().


// REM [str]
void CIncludeFile::IncludeRem(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 CIncludeFile::IncludeRem().

// WAIT
void CIncludeFile::IncludeWait(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_ERROR_SYNTAX;
		return;          
	}
	
	WaitCmd();    
                                       
}   // End of CIncludeFile::IncludeWait().                                       

/////////////////////////////////////////////////////////////////////////////
// Include sub-routine.

// Check the valid label.
BOOL CIncludeFile::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 CIncludeFile::IsLabel().


// Goto the special label.
void CIncludeFile::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_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 CIncludeFile::GotoLabel().


// Pass through the whole block.
void CIncludeFile::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_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_ERROR_BEGIN;
                return;
            }
        }
        else {
            m_nErrorID = INNER_ERROR_BEGIN;
            return;
        }
    }
        
    // Search the End-mark.
    do {
        m_pszLineBuf = m_pszOneLine;
        ReadFromFile();
        if ( NO_ERROR != m_nErrorID ) {
            m_nErrorID = INNER_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 CIncludeFile::PassBlockBranch().


// Search ELSE statement.
BOOL CIncludeFile::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 CIncludeFile::SearchELSE().


// Skip ELSE statement if ending IF block.
void CIncludeFile::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 CIncludeFile::SkipELSE().
                    

// Judge the condition.
BOOL CIncludeFile::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 CIncludeFile::JudgeCondition().

// Test ESC key or any other key.
int CIncludeFile::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;
}

//////////////////////////////// End of File ////////////////////////////////
