/***************************************************************************
**
**    $Header:   D:/EP196/SRC/LOG/SRCDLL/SRCEXP.CPP   1.0   15 Aug 1997 14:03:40   ZJRD  $
**
**    $Log:   D:/EP196/SRC/LOG/SRCDLL/SRCEXP.CPP  $
** 
**    Rev 1.0   15 Aug 1997 14:03:40   ZJRD
** Initial revision.
** 
**    Rev 1.1.7.0   19 Jun 1997 14:49:16   ZJRD
** 1.0c
** 
****************************************************************************/

// srcexp.cpp : implementation file
//

#include "stdafx.h"
#include "srcdll.h"
#include "srcgbl.h"
#include "srcaddr.h"
#include "bptdata.h"
#include "srcsht.h"
#include "srcload.h"
#include "srcdat.h"
#include "srcdoc.h"
#include "srcjump.h"
#include "srctext.h"
#include "srcview.h"
#include "srcprog.h"
#include "bptexp.h"

#include "address.h"
#include "abiextfn.h"
#include "ldrexp.h"
#include "symblsvr.h"

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

/////////////////////////////////////////////////////////////////////////////
// Static string

static char BASED_CODE szInt[] = "%d";
static char BASED_CODE szFile[] = "*.";

static char BASED_CODE szLoadOption[] = "Load Option";
static char BASED_CODE szCode[] = "Code";
static char BASED_CODE szSymbol[] = "Symbol";
static char BASED_CODE szDemand[] = "Demand";
static char BASED_CODE szStatus[] = "Status";
static char BASED_CODE szWarning[] = "Warning";
static char BASED_CODE szSystem[] = "System";

static char BASED_CODE szExtName[] = "Extension Name";
static char BASED_CODE szCount[] = "Count";
static char BASED_CODE szName[] = "Name";
static char BASED_CODE szC[] = ".C";
static char BASED_CODE szCPP[] = ".CPP";
static char BASED_CODE szASM[] = ".ASM";
static char BASED_CODE szA96[] = ".A96";

static char BASED_CODE szSearchOption[] = "Search Option";
static char BASED_CODE szWord[] = "Word";
static char BASED_CODE szCase[] = "Case";
static char BASED_CODE szDirect[] = "Direct";

static char BASED_CODE szSourcePath[] = "Source Path";
static char BASED_CODE szPath[] = "Path";

static char BASED_CODE szTargetExt[] = "Target Extension";

/////////////////////////////////////////////////////////////////////////////
// Error message

static char* BASED_CODE szErrorMsg[] = 
{
    "",                                            			// errNo = 0

    "Insufficient memory.",                                 // errMemory
    "File access error. Maybe the path is invalid.",		// errFile
    "Invalid address.",                                     // errAddr
    "Invalid input.",                                   	// errInput

    "Extension name length is longer than 3 characters.",	// errExtTooLong
    "Extension name is empty.",                             // errExtEmpty
    "Exist the same extension name.",                       // errExtExist
    "Illegal character in extension name.",                 // errExtChar

    "Exist the same path.",                                 // errPathSame

    "Breakpoint is at an invalid address.",                 // errBpAddr
    "Breakpoint is at an invalid symbol.",                  // errBpSymbol
    "Breakpoint address is invalid.",                       // errBpInput
    "Address is empty.",                                    // errBpEmpty
    "Already exist a breakpoint at this address.",          // errBpExist
    "Cannot open Breakpoint file.",                         // errBpFile
    "Breakpoint file format is invalid.",                   // errBpFormat
    "There is no breakpoints at this address.",             // errBpNoExist
    "There is not any breakpoints.",                       	// errBpNo
    "Breakpoint can not be set.",                     		// errBpSet
    "Breakpoint can not be gotton.",                		// errBpGet
    "Breakpoint can not be cleared.",                 		// errBpClr

    "Load file error.",                                     // errLoad

    "Target can not Step.",                                 // errStep
    "Target can not Step Over.",                            // errStepOver
    "Can not get CPU status.",                              // errCpuStatus
    "Browse from invalid address.",                         // errBrowseFrom
    "Jump to invalid address.",                             // errJumpTo

//	"Can not get PC.",										// errGetPC
	"EP is running.",										// errGetPC
//	"Can not set PC.",										// errSetPC
	"EP is running.",										// errSetPC

	"Target can not go.",									// errGo
	"EP is running.",										// errEPRun

    ""                                        				// errMax
};

/////////////////////////////////////////////////////////////////////////////
// Exported function

#ifdef __cplusplus
extern "C" {
#endif	// __cplusplus

BOOL WINAPI SrcInitSourceEnv()
{
	// Allocate path info list
	ASSERT(!::pSourcePathList);
	::pSourcePathList = new CStringList;

	// Allocate extension name info list
	ASSERT(!::pSourceExtNameList);
	::pSourceExtNameList = new CStringList;

	// Allocate search info list
	ASSERT(!::pSourceSearchList);
	::pSourceSearchList = new CStringList;
    
	// Allocate from info list
	ASSERT(!::pSourceFromList);
	::pSourceFromList = new CStringList;
    
	// Allocate jump info list
	ASSERT(!::pSourceJumpList);
	::pSourceJumpList = new CStringList;
    
    // Initial Module index array
    ASSERT(!::pSourceModuleDescList);
    ::pSourceModuleDescList = new CObList;

    // Allocate target path string
    ASSERT(!::pSrcTargetPath);
	::pSrcTargetPath = new CString;
	
    // Allocate target extension string
    ASSERT(!::pSrcTargetExt);
	::pSrcTargetExt = new CString;

	// Allocate source info list
	ASSERT(!::pSourceModuleInfoList);
	::pSourceModuleInfoList = new CObList;
	
	return TRUE;
}

void WINAPI SrcFreeSourceEnv()
{
	// Free path info list
	if ( ::pSourcePathList ) {
		::pSourcePathList->RemoveAll();
		delete ::pSourcePathList;
		::pSourcePathList = 0;
	}

	// Free extension name info list
	if ( ::pSourceExtNameList ) {
		::pSourceExtNameList->RemoveAll();
		delete ::pSourceExtNameList;
		::pSourceExtNameList = 0;
	}

	// Free search info list
	if ( ::pSourceSearchList ) {
		::pSourceSearchList->RemoveAll();
		delete ::pSourceSearchList;
		::pSourceSearchList = 0;
	}

	// Free from info list
	if ( ::pSourceFromList ) {
		::pSourceFromList->RemoveAll();
		delete ::pSourceFromList;
		::pSourceFromList = 0;
	}

	// Free jump info list
	if ( ::pSourceJumpList ) {
		::pSourceJumpList->RemoveAll();
		delete ::pSourceJumpList;
		::pSourceJumpList = 0;
	}
	
    // Free Module index array
    if ( ::pSourceModuleDescList ) {
    	POSITION pos = ::pSourceModuleDescList->GetHeadPosition();
    	while ( pos ) {
    		CModuleDesc* pObj = (CModuleDesc*)::pSourceModuleDescList->GetNext(pos);
    		delete pObj;
    	}
    	::pSourceModuleDescList->RemoveAll();
    	delete ::pSourceModuleDescList;
    	::pSourceModuleDescList = 0;
    }

	// Free target path string
	if ( ::pSrcTargetPath ) {
		delete ::pSrcTargetPath;
		::pSrcTargetPath = 0;
	}
	
	// Free target path string
	if ( ::pSrcTargetExt ) {
		delete ::pSrcTargetExt;
		::pSrcTargetExt = 0;
	}
	
	// Free source info list
	if ( ::pSourceModuleInfoList ) {
		POSITION pos = ::pSourceModuleInfoList->GetHeadPosition();
		while ( pos ) {
			CModuleInfo* pObj = (CModuleInfo*)::pSourceModuleInfoList->GetNext(pos);
			delete pObj;
		}
		::pSourceModuleInfoList->RemoveAll();
		delete ::pSourceModuleInfoList;
		::pSourceModuleInfoList = 0;
	}
}

void WINAPI SrcReadProfile()
{
	// Read Load option
	::nSrcLoadOption = 0;
    ::nSrcLoadOption |= AfxGetApp()->GetProfileInt(::szLoadOption, ::szCode, ::LDR_CODE);
    ::nSrcLoadOption |= AfxGetApp()->GetProfileInt(::szLoadOption, ::szSymbol, ::LDR_SYMBOL);
    ::nSrcLoadOption |= AfxGetApp()->GetProfileInt(::szLoadOption, ::szStatus, ::LDR_STATUS);
    ::nSrcLoadOption |= AfxGetApp()->GetProfileInt(::szLoadOption, ::szWarning, ::LDR_WARNING);
    ::nSrcLoadOption |= AfxGetApp()->GetProfileInt(::szLoadOption, ::szDemand, 0);
    ::nSrcLoadOption |= AfxGetApp()->GetProfileInt(::szLoadOption, ::szSystem, 0);

    // Read target extension name
    if ( ::pSrcTargetExt ) {
	    *::pSrcTargetExt = AfxGetApp()->GetProfileString(::szTargetExt, ::szExtName);
	}

	// Read Source Path
	::pSourcePathList->RemoveAll();
    int nCount = AfxGetApp()->GetProfileInt(::szSourcePath, ::szCount, -1);
    for ( int i(1); i <= nCount; i++ ) {
	    CString strNum("");
	    strNum.Format(::szInt, i);
	    CString strPath = AfxGetApp()->GetProfileString(::szSourcePath, CString(::szPath)+strNum);
	    if ( !strPath.IsEmpty() ) {
	    	::pSourcePathList->AddTail(strPath);
	    }
	}

	// Read Extension name
	::pSourceExtNameList->RemoveAll();
    nCount = AfxGetApp()->GetProfileInt(::szExtName, ::szCount, -1);
	if ( -1 == nCount ) {
		::pSourceExtNameList->AddTail(::szC);
		::pSourceExtNameList->AddTail(::szCPP);
		::pSourceExtNameList->AddTail(::szASM);
		::pSourceExtNameList->AddTail(::szA96);
	}
	else {
	    for ( int i(1); i <= nCount; i++ ) {
		    CString strNum("");
		    strNum.Format(::szInt, i);
		    CString strName = AfxGetApp()->GetProfileString(::szExtName, CString(::szName)+strNum);
		    if ( !strName.IsEmpty() ) {
		    	::pSourceExtNameList->AddTail(strName);
		    }
		}
	}

	// Read Search option
    ::bSrcSearchWord = AfxGetApp()->GetProfileInt(::szSearchOption, ::szWord, FALSE);
    ::bSrcSearchCase = AfxGetApp()->GetProfileInt(::szSearchOption, ::szCase, FALSE);
    ::nSrcSearchDirect = AfxGetApp()->GetProfileInt(::szSearchOption, ::szDirect, 1);
}

void WINAPI SrcWriteProfile()
{
	// Write Load option
    AfxGetApp()->WriteProfileInt(::szLoadOption, ::szCode, ::nSrcLoadOption & ::LDR_CODE);
    AfxGetApp()->WriteProfileInt(::szLoadOption, ::szSymbol, ::nSrcLoadOption & ::LDR_SYMBOL);
    AfxGetApp()->WriteProfileInt(::szLoadOption, ::szStatus, ::nSrcLoadOption & ::LDR_STATUS);
    AfxGetApp()->WriteProfileInt(::szLoadOption, ::szWarning, ::nSrcLoadOption & ::LDR_WARNING);
    AfxGetApp()->WriteProfileInt(::szLoadOption, ::szDemand, ::nSrcLoadOption & ::LDR_DEMAND);
    AfxGetApp()->WriteProfileInt(::szLoadOption, ::szSystem, ::nSrcLoadOption & ::LDR_SYSTEM);

    // Write target extension name
    if ( ::pSrcTargetExt ) {
		AfxGetApp()->WriteProfileString(::szTargetExt, ::szExtName, *::pSrcTargetExt);
	}

	// Write Source path
	if ( ::pSourcePathList ) {
		AfxGetApp()->WriteProfileInt(::szSourcePath, ::szCount, ::pSourcePathList->GetCount());

		POSITION pos = ::pSourcePathList->GetHeadPosition();
		int nIndex(1);
		while ( pos ) {
			CString strPath = ::pSourcePathList->GetNext(pos);
		    CString strNum("");
		    strNum.Format(::szInt, nIndex++);
			AfxGetApp()->WriteProfileString(::szSourcePath, CString(::szPath)+strNum, strPath);
		}
	}
	
	// Write Extension name
	if ( ::pSourceExtNameList ) {
		AfxGetApp()->WriteProfileInt(::szExtName, ::szCount, ::pSourceExtNameList->GetCount());
		
		POSITION pos = ::pSourceExtNameList->GetHeadPosition();
		int nIndex(1);
		while ( pos ) {
			CString strName = ::pSourceExtNameList->GetNext(pos);
		    CString strNum("");
		    strNum.Format(::szInt, nIndex++);
			AfxGetApp()->WriteProfileString(::szExtName, CString(::szName)+strNum, strName);
		}
	}
	
	// Write Search option
    AfxGetApp()->WriteProfileInt(::szSearchOption, ::szWord, ::bSrcSearchWord);
    AfxGetApp()->WriteProfileInt(::szSearchOption, ::szCase, ::bSrcSearchCase);
    AfxGetApp()->WriteProfileInt(::szSearchOption, ::szDirect, ::nSrcSearchDirect);
}

void WINAPI SrcLoadTargetFile(const CString& strFile)
{
	// Depend on LDR_STATUS
	CString strPath = strFile;
	BOOL bOK;
	if ( ::nSrcLoadOption & LDR_STATUS ) {
		// Open Load Progress dialog
		CSourceLoadProgressDlg(strPath).DoModal();
		bOK = !::bSrcAbortLoad;
		::bSrcAbortLoad = FALSE;
	}
	else {
		// No Load Progress dialog
		AfxGetApp()->BeginWaitCursor();
		bOK = ::StarterLoader(strPath, ::nSrcLoadOption);
		AfxGetApp()->EndWaitCursor();
	}

	// Update module info
	::SrcLoadCmd(bOK, strPath);
}

// Called after LoadCmd()
void WINAPI SrcLoadCmd(BOOL& bLoadOK, CString& strFile)
{
	// Close data hints
	::bSrcHintsOn = FALSE;
	
	// Clear all BPs
	CSourceAddr Addr(0,0);
	if ( ::BptClrBp(Addr) ) {
		// Empty bp list
		POSITION pos = ::BptGetBpList()->GetHeadPosition();
		while ( pos ) {
			CBpData* pObj = (CBpData*)::BptGetBpList()->GetNext(pos);
			delete pObj;
		}
		::BptGetBpList()->RemoveAll();
	}
	else {
//		::SrcDisplayErrorMessage(::errBpSet);
		return;
	}

	// Load file
	if ( bLoadOK ) {
		// Add to recent file list
		::SrcAddToRecentFileList(strFile);
	
		// Set target file name
		*::pSrcTargetPath = strFile;

		// Save module info to a global list
		::SrcGetAllModuleInfo();
	}
	else {
		if ( !::SrcIsLoadedSymbol() ) {
			// Destroy module info list
			::pSrcTargetPath->Empty();
	
			if ( ::pSourceModuleInfoList ) {
				POSITION posMod = ::pSourceModuleInfoList->GetHeadPosition();
				while ( posMod ) {
					CModuleInfo* pModObj = (CModuleInfo*)::pSourceModuleInfoList->GetNext(posMod);
					delete pModObj;
				}
				::pSourceModuleInfoList->RemoveAll();
			}
		}
		else {
			// Didn't destroy module info list, use the old symbol info
			return;
		}
	}

	// Initial Browse index
	::SrcAddModuleDesc(-1);

	// Update Source & Browse window
	::SrcUpdateSourceWindow(::srcOpen, TRUE);
	::SrcUpdateBrowseWindow(::brwOpen);
}

void WINAPI SrcBrowseModule()
{
	// Update Source & Browse window
	switch ( ::nSrcGroupEntry ) {
		case ::SRC_MAIN:
			if ( ::pBrowseWnd ) {
				::SrcUpdateBrowseWindow(::brwBrowse, TRUE);
				::nSrcGroupEntry = ::SRC_BROWSE;
			}
			else {
				::SrcUpdateSourceWindow(::srcBrowse, TRUE);
				::nSrcGroupEntry = ::SRC_SOURCE;
			}
			break;
		case ::SRC_SOURCE:
			::SrcUpdateSourceWindow(::srcBrowse);
			break;
		case ::SRC_BROWSE:
			::SrcUpdateBrowseWindow(::brwBrowse);
			break;
		default:
			ASSERT(FALSE);
			return;
	}
}

CStringList* WINAPI SrcGetSearchList()
{
	// Get Source Path list
	return ::pSourceSearchList;
}

void WINAPI SrcFilterMessage(MSG* pMsg)
{
	// Prefilter WM_KEYDOWN message
	if ( WM_KEYDOWN == pMsg->message && VK_RETURN == pMsg->wParam ) {
		// Search next
    	if ( ::pSourceWnd && ::SrcGetSearchComboHwnd() == pMsg->hwnd ) {
    		::pSourceWnd->GetActiveView()->SendMessage(WM_COMMAND, ID_EDIT_SEARCHNEXT);
    	}

		return;
	}

	// Prefilter WM_MOUSEMOVE message
    if ( WM_MOUSEMOVE == pMsg->message ) {
    	// Remark data tip
    	if ( ::pSourceWnd && ::pSourceWnd->GetActiveView()->GetSafeHwnd() != pMsg->hwnd ) {
    		::SrcHideDataTip();
	    }

	    // Send to Wizard bar
		CWnd* pWnd = AfxGetMainWnd();
		ASSERT(pWnd);
	    
	    CWnd* pWnd1 = pWnd->GetDescendantWindow(IDC_PROP);
	    CWnd* pWnd2 = pWnd->GetDescendantWindow(IDC_COMBO_SRC_WIZARDBAR_MODULE);
	    if ( pWnd1 && pWnd1->GetSafeHwnd() == pMsg->hwnd && pWnd1->IsWindowEnabled() ) {
			CPoint pt(pMsg->pt);
	    	pWnd1->GetParent()->ScreenToClient(&pt);
	    	pMsg->lParam = MAKELONG(pt.x, pt.y);
	    	pWnd1->GetParent()->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
	    }
	    else if ( pWnd2 && pWnd2->GetSafeHwnd() == pMsg->hwnd && pWnd2->IsWindowEnabled() ) {
			CPoint pt(pMsg->pt);
	    	pWnd2->GetParent()->ScreenToClient(&pt);
	    	pMsg->lParam = MAKELONG(pt.x, pt.y);
	    	pWnd2->GetParent()->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
	    }

    	// Remark hints tip
//    	if ( pWnd1 && pWnd1->GetSafeHwnd() != pMsg->hwnd && pWnd2 && pWnd2->GetSafeHwnd() != pMsg->hwnd ) {
//    		::SrcHideHintTip();
//    	}

		return;
    }
}

void WINAPI SrcOnGroup(const int nEntry)
{
	// Set Source Group entry
	::nSrcGroupEntry = ::SRC_MAIN;
	
	// Open Source Group
	CSourceSheet sheet(NULL, nEntry);
	sheet.DoModal();
}

void WINAPI SrcOnFileLoad()
{
	// Open file load dialog
	HINSTANCE hInstEXE = AfxGetResourceHandle();
	AfxSetResourceHandle(::SrcGetDLLHandle());

	CString strFilter;
	strFilter.LoadString(IDS_LOAD_FILTER);

	AfxSetResourceHandle(hInstEXE);

	CString strFile;
	if ( ::pSrcTargetExt->IsEmpty() ) {
		strFile = "";
	}
	else {
		strFile = ::szFile;
		strFile += *::pSrcTargetExt;
	}

	CSourceLoadDlg dlg(TRUE, NULL, strFile, OFN_HIDEREADONLY, strFilter);
	
	if ( IDOK == dlg.DoModal() ) {
		// Run loader
		::SrcLoadTargetFile(dlg.GetPathName());
		
		*::pSrcTargetExt = dlg.GetFileExt();
	}
}

BOOL WINAPI SrcAddrToText(const CSourceAddr& Addr, CString& strAddr)
{
	// Query from Address server
	::ADDRESS addr;
	addr.adrSpace = Addr.GetType();
	addr.adrAddress = Addr.GetAddr();

	if ( ::ADR_OK != ::AdrDadAddrToHex(addr, strAddr) ) {
		return FALSE;
	}

	return TRUE;
}

BOOL WINAPI SrcTextToAddr(const CString& strAddr, CSourceAddr& Addr)
{
	// Query from Address server
	::ADDRESS addr;
	if ( ::ADR_OK != ::AdrShellToAddr(strAddr, addr, ::SPACE_P0) ) {	// SPACE_PROGRAM
		return FALSE;
	}

	// Check space
	if ( addr.adrSpace < ::SPACE_P0 || addr.adrSpace > ::SPACE_P3 ) {
		return FALSE;
	}

	// Get CSourceAddr
	Addr = CSourceAddr(addr.adrAddress, addr.adrSpace);

	return TRUE;
}

BOOL WINAPI SrcAddrToSymbol(const CSourceAddr& Addr, CString& strSymbol)
{
	// Query from Address server
	::ADDRESS addr;
	addr.adrSpace = Addr.GetType();
	addr.adrAddress = Addr.GetAddr();

	return (::AdrAddrToSymbol(addr, strSymbol));
}

BOOL WINAPI SrcGetPC(CSourceAddr& AddrPC)
{
	// Call ABI
	DWORD dwPC;
	if ( ICE_OK != ::emuGetReg(0, 0, &dwPC) ) {
		return FALSE;
	}
    
    dwPC &= 0x3ffff;
    
	AddrPC.SetAddr(LOWORD(dwPC));
	AddrPC.SetType(HIWORD(dwPC)+(::MEM_P0-::MEM_UNDEFINED));

	return TRUE;
}

BOOL WINAPI SrcSetPC(const CSourceAddr& AddrPC)
{
	// Call ABI
	DWORD dwPC;
	dwPC = MAKELONG(AddrPC.GetAddr(), AddrPC.GetType()-(::MEM_P0-::MEM_UNDEFINED));

	return ( ICE_OK == ::emuSetReg(0, 0, dwPC) );
}

BOOL WINAPI SrcIsLoadedSymbol()
{
	// Query from Loader server
	return ::LdrIsSymbolLoaded();
}

int WINAPI SrcGetMode()
{
	// Get Source window mode
	if ( !::pSourceWnd ) {
		return ::modAsm;
	}

	return ((CSourceDocument*)::pSourceWnd->GetActiveDocument())->GetMode();
}

void WINAPI SrcSetMode(const int nMode)
{
	// Set Source window mode
	if ( ::pSourceWnd ) {
		((CSourceDocument*)::pSourceWnd->GetActiveDocument())->SetMode(nMode);
	}
}

void WINAPI SrcDisplayErrorMessage(const int nErrorID, const BOOL bInShell /* = FALSE */)
{
	// Get error message
//	CString strMsg;
//	strMsg.Format("Error ID = %d", nErrorID);
	CString strMsg = ::szErrorMsg[nErrorID];

	// UI: popup message box; Shell: show a line
	if ( !bInShell ) {
		AfxMessageBox(strMsg);
	}
	else {
		::SrcShowLine(strMsg);
	}
}

void WINAPI SrcOnRunJump()
{
	// Open Jump dialog
	CSourceJumpDlg dlg;
	if ( IDOK == dlg.DoModal() ) {
		if ( dlg.m_bPC ) {
			// Jump to initial PC
			CSourceAddr Addr;
			::SrcGetInitPC(Addr);
			if ( ::SrcSetPC(Addr) ) {
				::SrcUpdateSourceWindow(::srcReset, TRUE);
			}
			else {
				::SrcDisplayErrorMessage(::errSetPC);
			}
		}
		else {
			// Jump to head of the list
			CString strAddr = ::pSourceJumpList->GetHead();
			CSourceAddr Addr;
			if ( ::SrcTextToAddr(strAddr, Addr) ) {
				if ( ::SrcGetMode() == ::modMix && strAddr.Find('#') == -1 ) {
					::SrcSetMode(::modAsm);
				}
				if ( ::SrcSetPC(Addr) ) {
					::SrcUpdateSourceWindow(::srcReset, TRUE);
				}
				else {
					::SrcDisplayErrorMessage(::errSetPC);
				}
			}
		}
	}
}

void WINAPI SrcCursorLink(const DWORD dwAddr, const BYTE bType)
{
	// Check CPU status
	DWORD dwStatus;
	if ( ICE_OK != ::emuGetCpuStatus(&dwStatus) || (dwStatus & 0x10) ) {
		return;
	}

	// Open browse window
	if ( !::SrcIsBrowseWindowOpened() ) {
		::SrcUpdateBrowseWindow(::brwOpen, TRUE);
	}
	else if ( ::pBrowseWnd->IsIconic() ) {
    	::pBrowseWnd->ShowWindow(SW_RESTORE);
    }
	::pBrowseWnd->BringWindowToTop();

	// Cursor link is ON
	((CSourceView*)::pBrowseWnd->GetActiveView())->SetCursorLink(TRUE);
	((CSourceView*)::pBrowseWnd->GetActiveView())->CursorLink(CSourceAddr(dwAddr, bType));
}

void WINAPI SrcCursorLinkOff()
{
	// Check CPU status
	DWORD dwStatus;
	if ( ICE_OK != ::emuGetCpuStatus(&dwStatus) || (dwStatus & 0x10) ) {
		return;
	}

	// Open browse window
	if ( !::SrcIsBrowseWindowOpened() ) {
		return;
	}

	// Cursor link is OFF
	((CSourceView*)::pBrowseWnd->GetActiveView())->SetCursorLink(FALSE);
	((CSourceView*)::pBrowseWnd->GetActiveView())->UpdateBrowseWindow(::brwLink);
}

void WINAPI SrcInspectSource(const DWORD dwAddr, const BYTE bType)
{
	// Check CPU status
	DWORD dwStatus;
	if ( ICE_OK != ::emuGetCpuStatus(&dwStatus) || (dwStatus & 0x10) ) {
		return;
	}

	// Call from Stack window
	if ( !::SrcIsSourceWindowOpened() ) {
		::SrcUpdateSourceWindow(::srcOpen, TRUE);
	}
	else if ( ::pSourceWnd->IsIconic() ) {
    	::pSourceWnd->ShowWindow(SW_RESTORE);
    }
	::pSourceWnd->BringWindowToTop();

	((CSourceView*)::pSourceWnd->GetActiveView())->InspectSource(CSourceAddr(dwAddr, bType));
}

BOOL WINAPI SrcIsInSourceLine(const CSourceAddr& Addr, int& nLine, int& nStmt, SYM_DESCRIPTOR& dwModuleDesc)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get module range to compare
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pModuleObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		CSourceAddr Addr1 = pModuleObj->GetStart();
		CSourceAddr Addr2 = pModuleObj->GetEnd();
		if ( Addr >= Addr1 && Addr <= Addr2 ) {
			// Get module descriptor
			dwModuleDesc = pModuleObj->GetDesc();

			// Get line number
			CObList* pLineList = pModuleObj->GetLineList();
			if ( pLineList->IsEmpty() ) {
				return FALSE;
			}
			POSITION posLine = pLineList->GetHeadPosition();
			while ( posLine ) {
				CLineInfo* pLineObj = (CLineInfo*)pLineList->GetNext(posLine);
				CSourceAddr Addr1 = pLineObj->GetStart();
				CSourceAddr Addr2 = pLineObj->GetEnd();
				if ( Addr >= Addr1 && Addr <= Addr2 ) {
					nLine = pLineObj->GetLine();
					nStmt = -1;
					return TRUE;
				}
			}
		}
	}

	return FALSE;
}

BOOL WINAPI SrcIsLoadAbort()
{
	// Is abort the loading progress
	return ::bSrcAbortLoad;
}

BOOL WINAPI SrcIsSymbolic()
{
	// Is symbolic disassembly
	return ::bSrcSymbolic;
}

#ifdef __cplusplus
}
#endif	// __cplusplus
